|
||
|
|||||||
| Custom Script Releases This forum is where you can release your custom scripts for other users to use. Please note: By releasing your scripts here you are submitting them to the public and as such agree to make them public domain. The RunUO Team has made its software GPL for you to use and enjoy you should do the same for anything based off of RunUO. |
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 (permalink) |
|
Master of the Internet
Join Date: Aug 2003
Posts: 5,688
|
XmlSockets
v1.08a RunUO 2.0 version updated 6/18/06 ArteGordon Latest News: Version 1.08a has been updated to run under RunUO 2.0. - Lootpack mods package will be added. Summary: This set of attachments provides a system for adding sockets and socket augmentations to items and mobs. The XmlSockets attachment adds sockets that can be filled with augmentations that will enhance specific abilities. The XmlSocketable attachment enables player-addable sockets that can be added to the target object by players meeting customizable skill and resources requirements. Recent Updates: New to v1.08a updated 4/13/05 - added a new powerscroll transmutation recipe to the BoxOfTransmutation that takes any 3 powerscrolls of the same level, along with a legendary diamond, legendary ruby, and legendary emerald, and creates a new random powerscroll of the same level. - added some recipes for transmuting large and small BODs. Transmuting a small BOD and 2000 gp will give you a new random small BOD of the same type. Transmuting 20000 gp and a large BOD will give you a random large BOD of the same type. - the XmlMobFactions recipes are now properly commented out for those that arent using that system. New to v1.08 updated 3/10/05 - slightly modified the transmutation rules so that a recipe that specifies an ingredient in any quantity (quantity requirement of 0) still requires at least one of that ingredient. - added the option to specify a second skill requirement for socketing (thanks to Greystar for the suggestion). The XmlSocketable attachment now has 2 additional properties, RequiredSkill2 and MinSkillLevel2. By default MinSkillLevel2 is 0 so there is no second skill requirement. To support the requirement for a second skill, several new methods and constructors have been added. You can spawn an object with a second socketable skill requirement like this buckler/ATTACH/xmlsocketable,2,Tinkering,115,ArmsLore,70,gold,200 0 You can also randomly configure a socketed/socketable object with two skill requirements in scripts using the new ConfigureRandom overload method, like this XmlSockets.ConfigureRandom(this, 2.0, 0.1, 0.5, 3.0, 15.0, 50.0, SkillName.Veterinary, 100.0, SkillName.AnimalLore, 90.0, typeof(Emerald), 30); which will add a random socketable/socketed configuration to the target with a minimum 100 veterinary skill as well as a minimum 90 animal lore skill on socketing. There is also a new XmlSocketable constructor that accepts the additional skill requirements if you wish to add socketing to items in your own scripts. public XmlSocketable(int maxsockets, SkillName skillname, double minskilllevel, SkillName skillname2, double minskilllevel2, Type resource, int quantity) - added the ability to recover augmentations from sockets. Specific augmentations must have the ability to be recovered enabled by defining the CanRecover and OnRecover override methods in their scripts. If these are not defined for a particular augmentation, then they will not be recoverable. Augmentations that can be recovered and are already socketed into an item will be identified as such by clicking on their socket in the socket display gump. If the augmentation can be recovered you will see "Can be recovered" at the end of the description. Note that it is possible for an augmentation to be recoverable in certain items and not others if you wish, or even dependent on the individual trying to do the recovery (based on karma, fame, etc.). Just put the desired conditions in the CanRecover override method for the given augmentation. A version argument has been added to the CanRecover and OnRecover calls to allow you to make changes to augmentations but still control how older versions are handled. If you do make changes to existing augmentations you should override the Version property for that augmentation and return an updated value (the default is zero). If you make changes to the number of sockets used by an augmentation and previous versions of the augmentation been used, and you make the augmentation recoverable, then you should override the RecoverableSockets method and return the proper value based on the version number. - added a new recipe to the BoxOfTransmutation for recovering augmentations from items. Transmuting an augmented item and an AncientRuby will allow a random augmentation from the item to be recovered. - added the new HammerOfRecovery item that can be used to recover augmentations from a target. This can be used to recover augmentations from items or creatures. - added a new recipe to the BoxofTransmutation for creating a single use HammerOfRecovery from a regular hammer and an AncientRuby. This allows players with the proper skills and resources to create a hammer that could be given to other players to allow them to remove augmentations. - updated the crystal, radiant crystal, gem, and skull augments to support recovery. New to v1.07 updated 2/13/05 - fixed a possible crash bug involving the display of Socket properties on items that are on the generic vendor buy lists. - added a new transmutation container item, the BagOfResources that takes the arrow/bolt recipes and the hides/bandage recipe out of the BoxOfTransmutation. The BoxOfTransmutation now just contains augmentation related recipes. New to v1.06 updated 1/31/05 - added an interface specification to some of the existing augments to facilitate their use in the new transmutation system. - added the new items BoxOfTransmutation and MagicBasket. They can be made with limited or unlimited uses (setting the UsesRemaining property to a value less than zero gives unlimited use). - added the new BaseTransmutationContainer class that allows you to make containers that can magically create objects based upon specifiable recipes. The recipes are made up of lists of ingredients that when placed into the container in exactly the right quantity and with the correct properties, can be transformed into other objects. Each recipe can also optionally have multiple minimum skill and stat requirements. Two examples of transmutation devices are included. To test them out just [add magicbasket, or [add boxoftransmutation. They can also be made with limited uses with e.g. [add magicbasket 50 for a 50 use basket. The transmutation gump can be opened either by placing objects into the container, or by selecting the 'Use this device' context menu option. The MagicBasket has one recipe defined that requires cooking skill and makes a meat pie out when the following ingredients are used: 2 raw ribs, 1 garlic, 1 bowl of flour, 1 full pitcher of milk, 4 carrots. It requires 30 cooking skill, 30 dex, and 20 int. The BoxOfTransmutation has recipes for manipulating augments, and socketed weapons/armor, and a few other things. Here are the recipes that it has defined: HidesToBandages: will change any amount of hides into bandages Req - 50 str, 30 dex BoltsToArrows: will change any amount of bolts into half the quantity of arrows Req - 50 ArmsLore, 70 str, 30 dex ArrowsToBolts: will change any amount of arrows into half the quantity of bolts Req - 50 ArmsLore, 70 str, 30 dex UpgradeAncientAugment: will take 6 Ancient augments and convert them to a Legendary augment of the same type. Req - 50 Alchemy, 70 str, 30 dex, 40 int UpgradeLegendaryAugment: will take 3 Legendary augments and convert them to a Mythic augment of the same type. Req - 70 Alchemy, 70 str, 30 dex, 40 int UpgradeCrystalAugment: will take 3 Crystal augments and convert them to a Radiant augment of the same type. Req - 70 Alchemy, 70 str, 30 dex, 40 int SocketWeapon: will take any unsocketed weapon and a Rho rune augment and add a single socket to the weapon. Req - 50 Blacksmith, 70 str, 30 dex, 40 int SocketArmor: will take any unsocketed armor and a Rho rune augment and add a single socket to the armor. Req - 50 Blacksmith, 70 str, 30 dex, 40 int some additional recipes that allow various mob faction bonuses to be granted with recipes that use a combination of glimmering stone augments and gold are included. These require the XmlMobFactions system to be installed. These are commented out by default. If you have XmlMobFactions installed and you wish to use these, just uncomment them. An arbitrary number of additional recipes can be specified. You could also construct different transmutation container classes (derived from the BaseTransmutationContainer class) that implemented different recipe sets. New to v1.05 updated 1/22/05 - made an adjustment to the default gump art hues for augments so that they match the item hues. - added another gem augment (tourmaline) and updated the optional Loot.cs to reflect this. - added a set of glimmering stone augments that grant various skill bonuses. - updated installation instructions for 1.0.0 - updated the optional modified lootpack.cs/loot.cs files to 1.0.0 Description: This system makes use of the XmlSpawner2 attachment system and the XmlSpawner2 package must be installed to support it. You dont need to use the xmlspawners themselves, and it doesnt matter whether you use the standard distribution spawners or any other spawning system but you do need the XmlSpawner2 package installed. Because the attachment system neither requires nor makes any changes to serialization/deserializations of any item or mobile, it can be safely added and removed at any time now or in the future without interfering with any other systems that you might have installed. Note, this is intended as more of a development system for people to add custom content to their shards than just a drop-and-play system with a full complement of socket augmentations. While I have included a number of augmentations in the package that can be used as-is, they are intended to illustrate its features so that users can extend them with additional content. Features: Note that ANY object can in principle be socketed - weapons, armor, jewelry, clothing, tools, trees, doors, fruit, creatures, players, gems - anything. You just have to tag them with the sockets/socketable attachments using one of the methods described below. It is then the responsibility of the augment to determine what it can affect and what effect it has on the socketed object. Sockets Sockets allow target objects to be enhanced by providing slots in which specially designed augmentations can be placed. Different augmentations will confer different abilities to the target. Sockets can either come pre-existing on a target, or can be added by an individual with sufficient skill and resources. Socketability Individual objects can be flagged as being "socketable", by adding the XmlSocketable attachment which allows the maximum number of sockets, the type of skill and minimum skill level required to socket, and the resources used in socketing, to be specified. By default 100 Blacksmithing and 50 Valorite ingots are required to add a socket to a target. Augmenting To add an augmentation to a socket, both the augmentation and the item to be augmented must be in the players pack. To bring up the socket gump you must use the item identification skill on the item. In the gump, click on the socket and target the augmentation. By default, augmenting requires no resources and will always succeed. This behavior can be changed in the ConsumeOnAugment and OnAugment override methods for individual augmentations. After a socket has been filled with an augmentation, clicking on the socket will display the augmentation properties. Item Identification. This skill is used to display the sockets and socketability of target objects. Just use the skill and target an object (either items or creatures). Examples. Examples of socketed/socketable objects including tamable creatures such as a socketable dragon are included in the example .xml file socket1.xml. To try this out, place the file "socket1.xml" in your top level RunUO directory and execute the command "[xmlloadhere socket1.xml" It creates several bags of augmentations and various socketed and socketable items. The dragon can be socketed after it is tamed. Commands/Control Items: [addsocket - To add a socket to a socketable object the player issues the "[addsocket" command and targets an object. If the target is an item, then the item must be in the players backpack. If the target is a creature, then the creature must be under the players control. If socketing is successful, you will see the new socket in the socket gump. On each failure resources will still be consumed and there is a 10% chance that the target will be destroyed (this probability can be set by the static DefaultDestructionProbability variable in XmlSocket.cs). The difficulty of adding a socket depends on the minimum skill required by the object, the skill level of the player, and the existing number of sockets. The chance of succeeding in adding a socket can be displayed by using the Item Identification skill on a socketable object. SocketHammer - an item that provides the same functionality as the [addsocket command. Just double-click to use and target the object to be socketed. It can be given either limited (set UsesRemaining to a value > 0) or unlimited number of uses (set UsesRemaining to a value < 0). Adding sockets to items/mobs Manually to individual item/mobs - the xmlSockets attachment can be added to objects in several ways. It can be manually attached to any existing object with the "[addatt" command. For example "[addatt xmlsockets 4" will add 4 sockets to a targeted object. To scripts - Sockets can also be added to scripted objects. See the included script TestSocketedWeapon.cs for an example of this. To spawned objects - To add sockets to spawned objects use the ATTACH keyword in spawn entries such as this katana/ATTACH/xmlsockets,4 which would spawn a katana with 4 sockets. or orc/ADD/<katana/ATTACH/xmlsockets,4> would spawn an orc carrying the socketd katana. To try out the included example spawner .xml file, place the file "socket1.xml" in your top level RunUO directory and execute the command "[xmlloadhere socket1.xml" Making items/mobs socketable by players Manually to individual item/mobs - the xmlSocketable attachment can be added to objects in several ways. It can be manually attached to any existing object with the "[addatt" command. For example "[addatt xmlsocketable 4" will flag the target object as socketable and supporting a maximum of 4 player-added sockets. To scripts - Socketability can also be added to scripted objects. See the included script TestSocketedWeapon.cs for an example of this. To spawned objects - To add sockets to spawned objects use the ATTACH keyword in spawn entries such as this katana/ATTACH/xmlsocketable,4 which would spawn a katana supporting a maximum of 4 player-added sockets. buckler/ATTACH/xmlsocketable,2,Tinkering,115,gold,2000 which would spawn a buckler supporting a maximum of 2 player-added sockets that require a minimum of 115 Tinkering and 2000 gold to add. Installation: For 1.0.0 STEP 1: Install the latest XmlSpawner2 package. You can find it here XmlSpawner2. Make sure that you perform installation step 8 from that thread. I would also strongly suggest performing step 11 from that thread to allow socket properties to be automatically displayed. STEP 2: Place the scripts from this package into your custom scripts directory, or into the XmlAttachments area of your XmlSpawner2 installation. (anywhere in your Scripts folder is fine, these locations are suggested for organizational purposes only). Place the optional .xml example in the top level of your RunUO installation directory if you would like to try it out. If you have also installed the custom attacks/defenses system (XmlCustomAttacks) then you can extract the runeaugments.cs file. If you do not have that system, then remove runeaugments.cs from the Augments folder. STEP 3: (optional) To automatically add sockets and socketability to dropped weapons and armor and tamable creatures with some probability, you can make these changes to BaseArmor.cs, BaseWeapon.cs, BaseJewel.cs, and BaseCreature.cs. If you make this modification, all weapons/armor/tamable creatures will have some chance of having sockets when they are made. If you would rather put the modifications somewhere else, such as in LootPack.cs, or in scripts for specific weapons/armor/creatures/jewelry/etc. that would work as well. You could have random sockets/socketability automatically added to anything such as jewelry or any custom items that you have by adding in the XmlSockets.ConfigureRandom call into their constructors in the same way it is illustrated below. First, place the following line at the beginning of the files BaseArmor.cs, BaseWeapon.cs, BaseJewel.cs, and BaseCreature.cs Code:
using Server.Engines.XmlSpawner2; at the end of the BaseArmor constructor around line 1131 in Scripts/Items/Armor/BaseArmor.cs change this Code:
m_AosSkillBonuses = new AosSkillBonuses( this ); Code:
m_AosSkillBonuses = new AosSkillBonuses( this ); // mod to randomly add sockets and socketability features to armor. These settings will yield // 2% drop rate of socketed/socketable items // 0.1% chance of 5 sockets // 0.5% of 4 sockets // 3% chance of 3 sockets // 15% chance of 2 sockets // 50% chance of 1 socket // the remainder will be 0 socket (31.4% in this case) // uncomment the next line to prevent artifacts from being socketed // if(ArtifactRarity == 0) XmlSockets.ConfigureRandom(this, 2.0, 0.1, 0.5, 3.0, 15.0, 50.0); change this Code:
m_AosElementDamages = new AosElementAttributes( this ); Code:
m_AosElementDamages = new AosElementAttributes( this ); // mod to randomly add sockets and socketability features to weapons. These settings will yield // 2% drop rate of socketed/socketable items // 0.1% chance of 5 sockets // 0.5% of 4 sockets // 3% chance of 3 sockets // 15% chance of 2 sockets // 50% chance of 1 socket // the remainder will be 0 socket (31.4% in this case) // uncomment the next line to prevent artifacts from being socketed // if(ArtifactRarity == 0) XmlSockets.ConfigureRandom(this, 2.0, 0.1, 0.5, 3.0, 15.0, 50.0); change this Code:
Layer = layer; Code:
Layer = layer; // mod to randomly add sockets and socketability features to weapons. These settings will yield // 2% drop rate of socketed/socketable items // 0.1% chance of 5 sockets // 0.5% of 4 sockets // 3% chance of 3 sockets // 15% chance of 2 sockets // 50% chance of 1 socket // the remainder will be 0 socket (31.4% in this case) // uncomment the next line to prevent artifacts from being socketed // if(ArtifactRarity == 0) XmlSockets.ConfigureRandom(this, 2.0, 0.1, 0.5, 3.0, 15.0, 50.0); Code:
public override void OnBeforeSpawn( Point3D location, Map m )
{
if ( Paragon.CheckConvert( this, location, m ) )
IsParagon = true;
base.OnBeforeSpawn( location, m );
}
Code:
public override void OnBeforeSpawn( Point3D location, Map m )
{
if ( Paragon.CheckConvert( this, location, m ) )
IsParagon = true;
// mod to randomly add socket features to tamable creatures. These settings will yield
// 2% drop rate of socketed/socketable items
// 0.1% chance of 5 sockets
// 0.5% of 4 sockets
// 3% chance of 3 sockets
// 15% chance of 2 sockets
// 50% chance of 1 socket
// the remainder will be 0 socket (31.4% in this case)
// Adding new sockets will require a minimum of 100 Veterinary skill and 30 emeralds
if(Tamable)
XmlSockets.ConfigureRandom(this, 2.0, 0.1, 0.5, 3.0, 15.0, 50.0, SkillName.Veterinary, 100.0, typeof(Emerald), 30);
base.OnBeforeSpawn( location, m );
}
STEP 4: (optional) I have added modified distro 1.0.0 versions of Loot.cs and LootPack.cs that will give random lootpack drops of augmentations. The frequency of drop is low (about the same as instruments), and the definitions include the rune augmentations (if you dont have runeaugments.cs installed then comment out the sections referring to the runes). To use them, either replace the distro Scripts/Misc/LootPack.cs and Scripts/Misc/Loot.cs with the versions in the SocketsLootMod.zip file (always make backups of your original scripts), or just look in those files for the changes marked "ARTEGORDONMOD", and incorporate them into your existing lootpack.cs and loot.cs files. Note, I intentionally renamed the files with ._cs extensions so that they wouldnt cause problems if you extracted them into your scripts area. The extensions need to be changed to .cs if you wish to use them as replacements for the distro loot.cs and lootpack.cs scripts. Changelog: Version 1.04 updated 12/26/04 - added support for adding augments via scripts instead of just via player targeting (thanks to sUpplier1 for the suggestion). - added a new example of this feature in testsocketedweapon.cs (case 3) - minor change in reporting of objects that have already reached their maximum number of allowed sockets. It no longer describes the requirements and socketing chance for such objects. - minor change in property list display of socketable objects. The resource and skill requirements will no longer be displayed on mouseover. That info can still be obtained by using the Item Identification skill on the object. - the random socket/socketable configuration method "ConfigureRandom" will no longer create 0-socketable configurations (thanks to sUpplier1 for pointing this out). - added jewelry support to the crystal and radiant crystal augments. - modified installation step 3 to support randomly socketed jewelry drops and to allow you to exclude the possibility of socketed artifacts if you like. Version 1.03 updated 12/07/04 - added 29 new augmentations in two sets, Crystals (2 socket) and RadiantCrystals (4 socket). - modified the optional Loot.cs file to support lootpack drops of these augments. - updated the socket1.xml example to include a bags of the new augments. Version 1.02 update 12/03/04 - added an additional XmlSockets constructor that allows the default requirement for socketed items to be in the players pack when augmenting to be overridden. "[addatt xmlsockets 1 false" for example would allow you to attach a single socket that did not require the socketed item to be in the players pack when augmenting. This can be useful for allowing items in the world such as doors to be augmented. - added a new augmentation called a "keyaugment". This can be used to open doors and chests by assigning it a KeyValue that matches the KeyValue of the door/chest, and then using it to augment a socket on the door/chest. A skill requirement can also be assigned to it as can the number of uses. This is an example of placing additional constraints on the use of augmentations in the OnAugment method. - added an example of a socketed door and socketed chest that open when a master thief places the proper keyaugment into the socket. This can be tested by loading the keyaugment.xml example. Use item identify on the door named "Sesame" to bring up the socket gump, and then augment it with the special "Sesame" rune (you must have at least 100 lockpicking). After opening, the door resockets itself so that it has to be augmented again to be opened. The chest can be opened in the same way with the "Sesame's treasure" keyaugment that has the form of a skull. That one requires 100 Stealing to use. Notice how the keyaugment to open the door does not get destroyed after it is used, while the one to the chest does. This is due to the UsesRemaining property that has been set on it. Setting this to a value < 0, gives it unlimited uses. Setting it to a value > 0 gives it the specified number of uses (a value of 1 would be the default single-use case). - shifted the SocketAugmentations entries in the optional LootPack.cs mods to the ends of each lootpack list to reduce luck-enhanced chance of dropping augments. The way lootpacks work, entries near the top of the list have the greatest chance of being added due to luck, and the luck-computed drop probability is generally much higher than the drop chance specified for each entry (particularly if the entry chance is supposed to be low which is why you get so many luck-related magic item drops on poor lootpack mobs). - added a range check for socketing creatures (maximum distance 2) Version 1.01 updated 12/1/04 - added a set of Mythic augments that are 3 socket augmentations in addition to the Ancient (1 socket) and Legendary (2 socket) types. Loot.cs in the optional SocketsLootMod-v101.zip was modified to reflect the change. - the augment examples have been organized into a separate folder replacing the previous files otheraugments.cs, gemaugments.cs, and runeaugments.cs (you should get rid of those if you had them from an earlier installation or your will get errors about things being already defined). - the socket1.xml example has been updated with the new augments. - added the SocketHammer item as an alternative to the [addsocket command to add sockets to target objects. Just "[add sockethammer", double click the hammer and target the object to be socketed. Setting the number of uses (UsesRemaining property) to a value greater than zero will give it limited uses. Setting it less than zero makes it unlimited. - having an item with an existing socket number that exceeds the maxsockets indicated in its XmlSocketable attachment will now automatically have that max adjusted to match the current number of existing sockets. It is basically just a cosmetic change to avoid confusion in the way the available sockets are reported. Some players were getting confused by items that indicated the maxsockets allowed as 1, and the available sockets as 2 for example. This just meant that the item already had 2 sockets, but that you could not add any additional sockets beyond 1.
__________________
The first line of the first rule in the forum rules and guidelines "Be respectful of others. " For questions, information, and support for XmlSpawner and its addons, visit the XmlSpawner Support Forum |
|
|
|
|
|
#2 (permalink) | |
|
Forum Expert
Join Date: May 2005
Age: 18
Posts: 270
|
Arte sorry to be a bother, but on your post it says
Quote:
![]()
__________________
Burning Venganc |
|
|
|
|
|
|
#3 (permalink) | ||
|
Master of the Internet
Join Date: Aug 2003
Posts: 5,688
|
Quote:
Quote:
__________________
The first line of the first rule in the forum rules and guidelines "Be respectful of others. " For questions, information, and support for XmlSpawner and its addons, visit the XmlSpawner Support Forum Last edited by ArteGordon; 07-03-2006 at 05:19 PM. |
||
|
|
|
|
|
#4 (permalink) |
|
Forum Expert
Join Date: May 2005
Age: 18
Posts: 270
|
oops sorry
also, shouldnt there be a modified Itemid? because atm itemid doesnt bring up the sockets thing like its meant to...
__________________
Burning Venganc |
|
|
|
|
|
#5 (permalink) | |||
|
Master of the Internet
Join Date: Aug 2003
Posts: 5,688
|
Quote:
Quote:
Quote:
__________________
The first line of the first rule in the forum rules and guidelines "Be respectful of others. " For questions, information, and support for XmlSpawner and its addons, visit the XmlSpawner Support Forum |
|||
|
|
|
|
|
#6 (permalink) |
|
Forum Expert
Join Date: May 2005
Age: 18
Posts: 270
|
Ah thanks alot, feel a bit stupid now :P
__________________
Burning Venganc |
|
|
|
|
|
#7 (permalink) |
|
Newbie
Join Date: Jul 2005
Age: 43
Posts: 31
|
Hi Artgordon I love this sytem been playibg with it on another so though must have it on my new 2.0rc1 server but am having this error come up HTML Code:
Scripts: One or more scripts failed to compile or no script files were found.
- Press return to exit, or R to try again.
Scripts: Compiling C# scripts...failed (2 errors, 5 warnings)
Errors:
+ custom/system's and tools/XmlSpawner2_20_v312_2of3/XmlAttach/XmlSockets-20-v1
08a/Base mods for sockets/BaseWeapon.cs:
CS0103: Line 2732: The name 'XmlSockets' does not exist in the current conte
xt
+ custom/system's and tools/XmlSpawner2_20_v312_2of3/XmlAttach/XmlSockets-20-v1
08a/Base mods for sockets/BaseJewel.cs:
CS0103: Line 103: The name 'XmlSockets' does not exist in the current contex
t
Scripts: One or more scripts failed to compile or no script files were found.
- Press return to exit, or R to try again.
Basejewel.cs Code:
using System;
using Server.Engines.Craft;
using Server.Engines.XmlSpawner2;
namespace Server.Items
{
public enum GemType
{
None,
StarSapphire,
Emerald,
Sapphire,
Ruby,
Citrine,
Amethyst,
Tourmaline,
Amber,
Diamond
}
public abstract class BaseJewel : Item, ICraftable
{
private AosAttributes m_AosAttributes;
private AosElementAttributes m_AosResistances;
private AosSkillBonuses m_AosSkillBonuses;
private CraftResource m_Resource;
private GemType m_GemType;
[CommandProperty( AccessLevel.GameMaster )]
public AosAttributes Attributes
{
get{ return m_AosAttributes; }
set{}
}
[CommandProperty( AccessLevel.GameMaster )]
public AosElementAttributes Resistances
{
get{ return m_AosResistances; }
set{}
}
[CommandProperty( AccessLevel.GameMaster )]
public AosSkillBonuses SkillBonuses
{
get{ return m_AosSkillBonuses; }
set{}
}
[CommandProperty( AccessLevel.GameMaster )]
public CraftResource Resource
{
get{ return m_Resource; }
set{ m_Resource = value; Hue = CraftResources.GetHue( m_Resource ); }
}
[CommandProperty( AccessLevel.GameMaster )]
public GemType GemType
{
get{ return m_GemType; }
set{ m_GemType = value; InvalidateProperties(); }
}
public override int PhysicalResistance{ get{ return m_AosResistances.Physical; } }
public override int FireResistance{ get{ return m_AosResistances.Fire; } }
public override int ColdResistance{ get{ return m_AosResistances.Cold; } }
public override int PoisonResistance{ get{ return m_AosResistances.Poison; } }
public override int EnergyResistance{ get{ return m_AosResistances.Energy; } }
public virtual int BaseGemTypeNumber{ get{ return 0; } }
public override int LabelNumber
{
get
{
if ( m_GemType == GemType.None )
return base.LabelNumber;
return BaseGemTypeNumber + (int)m_GemType - 1;
}
}
public virtual int ArtifactRarity{ get{ return 0; } }
public BaseJewel( int itemID, Layer layer ) : base( itemID )
{
m_AosAttributes = new AosAttributes( this );
m_AosResistances = new AosElementAttributes( this );
m_AosSkillBonuses = new AosSkillBonuses( this );
m_Resource = CraftResource.Iron;
m_GemType = GemType.None;
Layer = layer;
// mod to randomly add sockets and socketablility features to jewels. These settings will yield
// 2% drop rate of socketed/socketable items
// 0.1% chance of 5 sockets
// 0.5 of 4 sockets
// 3% chance of 3 sockets
// 15% chance of 2 sockets
// 50% chance of 1 socket
// the remainder will be 0 socket (31.4% in this case)
// uncomment the following line to prevent artifacts from being socketed
// if(ArtifactRarity == 0)
XmlSockets.ConfigureRandom(this, 2.0, 0.1, 0.5, 3.0, 15.0, 50.0);
}
public override void OnAdded( object parent )
{
if ( Core.AOS && parent is Mobile )
{
Mobile from = (Mobile)parent;
m_AosSkillBonuses.AddTo( from );
int strBonus = m_AosAttributes.BonusStr;
int dexBonus = m_AosAttributes.BonusDex;
int intBonus = m_AosAttributes.BonusInt;
if ( strBonus != 0 || dexBonus != 0 || intBonus != 0 )
{
string modName = this.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( object parent )
{
if ( Core.AOS && parent is Mobile )
{
Mobile from = (Mobile)parent;
m_AosSkillBonuses.Remove();
string modName = this.Serial.ToString();
from.RemoveStatMod( modName + "Str" );
from.RemoveStatMod( modName + "Dex" );
from.RemoveStatMod( modName + "Int" );
from.CheckStatTimers();
}
}
public BaseJewel( Serial serial ) : base( serial )
{
}
public override void GetProperties( ObjectPropertyList list )
{
base.GetProperties( list );
m_AosSkillBonuses.GetProperties( list );
int prop;
if ( (prop = ArtifactRarity) > 0 )
list.Add( 1061078, prop.ToString() ); // artifact rarity ~1_val~
if ( (prop = m_AosAttributes.WeaponDamage) != 0 )
list.Add( 1060401, prop.ToString() ); // damage increase ~1_val~%
if ( (prop = m_AosAttributes.DefendChance) != 0 )
list.Add( 1060408, prop.ToString() ); // defense chance increase ~1_val~%
if ( (prop = m_AosAttributes.BonusDex) != 0 )
list.Add( 1060409, prop.ToString() ); // dexterity bonus ~1_val~
if ( (prop = m_AosAttributes.EnhancePotions) != 0 )
list.Add( 1060411, prop.ToString() ); // enhance potions ~1_val~%
if ( (prop = m_AosAttributes.CastRecovery) != 0 )
list.Add( 1060412, prop.ToString() ); // faster cast recovery ~1_val~
if ( (prop = m_AosAttributes.CastSpeed) != 0 )
list.Add( 1060413, prop.ToString() ); // faster casting ~1_val~
if ( (prop = m_AosAttributes.AttackChance) != 0 )
list.Add( 1060415, prop.ToString() ); // hit chance increase ~1_val~%
if ( (prop = m_AosAttributes.BonusHits) != 0 )
list.Add( 1060431, prop.ToString() ); // hit point increase ~1_val~
if ( (prop = m_AosAttributes.BonusInt) != 0 )
list.Add( 1060432, prop.ToString() ); // intelligence bonus ~1_val~
if ( (prop = m_AosAttributes.LowerManaCost) != 0 )
list.Add( 1060433, prop.ToString() ); // lower mana cost ~1_val~%
if ( (prop = m_AosAttributes.LowerRegCost) != 0 )
list.Add( 1060434, prop.ToString() ); // lower reagent cost ~1_val~%
if ( (prop = m_AosAttributes.Luck) != 0 )
list.Add( 1060436, prop.ToString() ); // luck ~1_val~
if ( (prop = m_AosAttributes.BonusMana) != 0 )
list.Add( 1060439, prop.ToString() ); // mana increase ~1_val~
if ( (prop = m_AosAttributes.RegenMana) != 0 )
list.Add( 1060440, prop.ToString() ); // mana regeneration ~1_val~
if ( (prop = m_AosAttributes.NightSight) != 0 )
list.Add( 1060441 ); // night sight
if ( (prop = m_AosAttributes.ReflectPhysical) != 0 )
list.Add( 1060442, prop.ToString() ); // reflect physical damage ~1_val~%
if ( (prop = m_AosAttributes.RegenStam) != 0 )
list.Add( 1060443, prop.ToString() ); // stamina regeneration ~1_val~
if ( (prop = m_AosAttributes.RegenHits) != 0 )
list.Add( 1060444, prop.ToString() ); // hit point regeneration ~1_val~
if ( (prop = m_AosAttributes.SpellChanneling) != 0 )
list.Add( 1060482 ); // spell channeling
if ( (prop = m_AosAttributes.SpellDamage) != 0 )
list.Add( 1060483, prop.ToString() ); // spell damage increase ~1_val~%
if ( (prop = m_AosAttributes.BonusStam) != 0 )
list.Add( 1060484, prop.ToString() ); // stamina increase ~1_val~
if ( (prop = m_AosAttributes.BonusStr) != 0 )
list.Add( 1060485, prop.ToString() ); // strength bonus ~1_val~
if ( (prop = m_AosAttributes.WeaponSpeed) != 0 )
list.Add( 1060486, prop.ToString() ); // swing speed increase ~1_val~%
base.AddResistanceProperties( list );
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 2 ); // version
writer.WriteEncodedInt( (int) m_Resource );
writer.WriteEncodedInt( (int) m_GemType );
m_AosAttributes.Serialize( writer );
m_AosResistances.Serialize( writer );
m_AosSkillBonuses.Serialize( writer );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 2:
{
m_Resource = (CraftResource)reader.ReadEncodedInt();
m_GemType = (GemType)reader.ReadEncodedInt();
goto case 1;
}
case 1:
{
m_AosAttributes = new AosAttributes( this, reader );
m_AosResistances = new AosElementAttributes( this, reader );
m_AosSkillBonuses = new AosSkillBonuses( this, reader );
if ( Core.AOS && Parent is Mobile )
m_AosSkillBonuses.AddTo( (Mobile)Parent );
int strBonus = m_AosAttributes.BonusStr;
int dexBonus = m_AosAttributes.BonusDex;
int intBonus = m_AosAttributes.BonusInt;
if ( Parent is Mobile && (strBonus != 0 || dexBonus != 0 || intBonus != 0) )
{
Mobile m = (Mobile)Parent;
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 ) );
}
if ( Parent is Mobile )
((Mobile)Parent).CheckStatTimers();
break;
}
case 0:
{
m_AosAttributes = new AosAttributes( this );
m_AosResistances = new AosElementAttributes( this );
m_AosSkillBonuses = new AosSkillBonuses( this );
break;
}
}
if ( version < 2 )
{
m_Resource = CraftResource.Iron;
m_GemType = GemType.None;
}
}
#region ICraftable Members
public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue )
{
Type resourceType = typeRes;
if ( resourceType == null )
resourceType = craftItem.Ressources.GetAt( 0 ).ItemType;
Resource = CraftResources.GetFromType( resourceType );
CraftContext context = craftSystem.GetContext( from );
if ( context != null && context.DoNotColor )
Hue = 0;
if ( 1 < craftItem.Ressources.Count )
{
resourceType = craftItem.Ressources.GetAt( 1 ).ItemType;
if ( resourceType == typeof( StarSapphire ) )
GemType = GemType.StarSapphire;
else if ( resourceType == typeof( Emerald ) )
GemType = GemType.Emerald;
else if ( resourceType == typeof( Sapphire ) )
GemType = GemType.Sapphire;
else if ( resourceType == typeof( Ruby ) )
GemType = GemType.Ruby;
else if ( resourceType == typeof( Citrine ) )
GemType = GemType.Citrine;
else if ( resourceType == typeof( Amethyst ) )
GemType = GemType.Amethyst;
else if ( resourceType == typeof( Tourmaline ) )
GemType = GemType.Tourmaline;
else if ( resourceType == typeof( Amber ) )
GemType = GemType.Amber;
else if ( resourceType == typeof( Diamond ) )
GemType = GemType.Diamond;
}
return 1;
}
#endregion
}
}
Code:
using System;
using System.Text;
using System.Collections;
using Server.Network;
using Server.Targeting;
using Server.Mobiles;
using Server.Spells;
using Server.Spells.Necromancy;
using Server.Spells.Bushido;
using Server.Spells.Ninjitsu;
using Server.Factions;
using Server.Engines.Craft;
using Server.Engines.XmlSpawner2;
using System.Collections.Generic;
namespace Server.Items
{
public interface ISlayer
{
SlayerName Slayer { get; set; }
SlayerName Slayer2 { get; set; }
}
public abstract class BaseWeapon : Item, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability
{
#region Factions
private FactionItem m_FactionState;
public FactionItem FactionItemState
{
get{ return m_FactionState; }
set
{
m_FactionState = value;
if ( m_FactionState == null )
Hue = CraftResources.GetHue( Resource );
LootType = ( m_FactionState == null ? LootType.Regular : LootType.Blessed );
}
}
#endregion
/* 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
*/
#region Var declarations
// 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;
private bool m_PlayerConstructed;
private bool m_Cursed; // Is this weapon cursed via Curse Weapon necromancer spell? Temporary; not serialized.
private bool m_Consecrated; // Is this weapon blessed via Consecrate Weapon paladin ability? Temporary; not serialized.
private AosAttributes m_AosAttributes;
private AosWeaponAttributes m_AosWeaponAttributes;
private AosSkillBonuses m_AosSkillBonuses;
private AosElementAttributes m_AosElementDamages;
// 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 int m_Speed;
private int m_MaxRange;
private SkillName m_Skill;
private WeaponType m_Type;
private WeaponAnimation m_Animation;
#endregion
#region Virtual Properties
public virtual WeaponAbility PrimaryAbility{ get{ return null; } }
public virtual WeaponAbility SecondaryAbility{ get{ return null; } }
public virtual int DefMaxRange{ get{ return 1; } }
public virtual int DefHitSound{ get{ return 0; } }
public virtual int DefMissSound{ get{ return 0; } }
public virtual SkillName DefSkill{ get{ return SkillName.Swords; } }
public virtual WeaponType DefType{ get{ return WeaponType.Slashing; } }
public virtual WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Slash1H; } }
public virtual int AosStrengthReq{ get{ return 0; } }
public virtual int AosDexterityReq{ get{ return 0; } }
public virtual int AosIntelligenceReq{ get{ return 0; } }
public virtual int AosMinDamage{ get{ return 0; } }
public virtual int AosMaxDamage{ get{ return 0; } }
public virtual int AosSpeed{ get{ return 0; } }
public virtual int AosMaxRange{ get{ return DefMaxRange; } }
public virtual int AosHitSound{ get{ return DefHitSound; } }
public virtual int AosMissSound{ get{ return DefMissSound; } }
public virtual SkillName AosSkill{ get{ return DefSkill; } }
public virtual WeaponType AosType{ get{ return DefType; } }
public virtual WeaponAnimation AosAnimation{ get{ return DefAnimation; } }
public virtual int OldStrengthReq{ get{ return 0; } }
public virtual int OldDexterityReq{ get{ return 0; } }
public virtual int OldIntelligenceReq{ get{ return 0; } }
public virtual int OldMinDamage{ get{ return 0; } }
public virtual int OldMaxDamage{ get{ return 0; } }
public virtual int OldSpeed{ get{ return 0; } }
public virtual int OldMaxRange{ get{ return DefMaxRange; } }
public virtual int OldHitSound{ get{ return DefHitSound; } }
public virtual int OldMissSound{ get{ return DefMissSound; } }
public virtual SkillName OldSkill{ get{ return DefSkill; } }
public virtual WeaponType OldType{ get{ return DefType; } }
public virtual WeaponAnimation OldAnimation{ get{ return DefAnimation; } }
public virtual int InitMinHits{ get{ return 0; } }
public virtual int InitMaxHits{ get{ return 0; } }
public override int PhysicalResistance{ get{ return m_AosWeaponAttributes.ResistPhysicalBonus; } }
public override int FireResistance{ get{ return m_AosWeaponAttributes.ResistFireBonus; } }
public override int ColdResistance{ get{ return m_AosWeaponAttributes.ResistColdBonus; } }
public override int PoisonResistance{ get{ return m_AosWeaponAttributes.ResistPoisonBonus; } }
public override int EnergyResistance{ get{ return m_AosWeaponAttributes.ResistEnergyBonus; } }
public virtual SkillName AccuracySkill { get { return SkillName.Tactics; } }
#endregion
#region Getters & Setters
[CommandProperty( AccessLevel.GameMaster )]
public AosAttributes Attributes
{
get{ return m_AosAttributes; }
set{}
}
[CommandProperty( AccessLevel.GameMaster )]
public AosWeaponAttributes WeaponAttributes
{
get{ return m_AosWeaponAttributes; }
set{}
}
[CommandProperty( AccessLevel.GameMaster )]
public AosSkillBonuses SkillBonuses
{
get{ return m_AosSkillBonuses; }
set{}
}
[CommandProperty( AccessLevel.GameMaster )]
public AosElementAttributes AosElementDamages
{
get { return m_AosElementDamages; }
set { }
}
[CommandProperty( AccessLevel.GameMaster )]
public bool Cursed
{
get{ return m_Cursed; }
set{ m_Cursed = value; }
}
[CommandProperty( AccessLevel.GameMaster )]
public bool Consecrated
{
get{ return m_Consecrated; }
set{ m_Consecrated = value; }
}
[CommandProperty( AccessLevel.GameMaster )]
public bool Identified
{
get{ return m_Identified; }
set{ m_Identified = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public int HitPoints
{
get{ return 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{ return m_MaxHits; }
set{ m_MaxHits = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public int PoisonCharges
{
get{ return m_PoisonCharges; }
set{ m_PoisonCharges = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public Poison Poison
{
get{ return m_Poison; }
set{ m_Poison = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public WeaponQuality Quality
{
get{ return m_Quality; }
set{ UnscaleDurability(); m_Quality = value; ScaleDurability(); InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public Mobile Crafter
{
get{ return m_Crafter; }
set{ m_Crafter = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public SlayerName Slayer
{
get{ return m_Slayer; }
set{ m_Slayer = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public SlayerName Slayer2
{
get { return m_Slayer2; }
set { m_Slayer2 = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public CraftResource Resource
{
get{ return m_Resource; }
set{ UnscaleDurability(); m_Resource = value; Hue = CraftResources.GetHue( m_Resource ); InvalidateProperties(); ScaleDurability(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public WeaponDamageLevel DamageLevel
{
get{ return m_DamageLevel; }
set{ m_DamageLevel = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public WeaponDurabilityLevel DurabilityLevel
{
get{ return m_DurabilityLevel; }
set{ UnscaleDurability(); m_DurabilityLevel = value; InvalidateProperties(); ScaleDurability(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public bool PlayerConstructed
{
get{ return m_PlayerConstructed; }
set{ m_PlayerConstructed = value; }
}
[CommandProperty( AccessLevel.GameMaster )]
public int MaxRange
{
get{ return ( m_MaxRange == -1 ? Core.AOS ? AosMaxRange : OldMaxRange : m_MaxRange ); }
set{ m_MaxRange = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public WeaponAnimation Animation
{
get{ return ( m_Animation == (WeaponAnimation)(-1) ? Core.AOS ? AosAnimation : OldAnimation : m_Animation ); }
set{ m_Animation = value; }
}
[CommandProperty( AccessLevel.GameMaster )]
public WeaponType Type
{
get{ return ( m_Type == (WeaponType)(-1) ? Core.AOS ? AosType : OldType : m_Type ); }
set{ m_Type = value; }
}
[CommandProperty( AccessLevel.GameMaster )]
public SkillName Skill
{
get{ return ( m_Skill == (SkillName)(-1) ? Core.AOS ? AosSkill : OldSkill : m_Skill ); }
set{ m_Skill = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public int HitSound
{
get{ return ( m_HitSound == -1 ? Core.AOS ? AosHitSound : OldHitSound : m_HitSound ); }
set{ m_HitSound = value; }
}
[CommandProperty( AccessLevel.GameMaster )]
public int MissSound
{
get{ return ( m_MissSound == -1 ? Core.AOS ? AosMissSound : OldMissSound : m_MissSound ); }
set{ m_MissSound = value; }
}
[CommandProperty( AccessLevel.GameMaster )]
public int MinDamage
{
get{ return ( m_MinDamage == -1 ? Core.AOS ? AosMinDamage : OldMinDamage : m_MinDamage ); }
set{ m_MinDamage = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public int MaxDamage
{
get{ return ( m_MaxDamage == -1 ? Core.AOS ? AosMaxDamage : OldMaxDamage : m_MaxDamage ); }
set{ m_MaxDamage = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public int Speed
{
get{ return ( m_Speed == -1 ? Core.AOS ? AosSpeed : OldSpeed : m_Speed ); }
set{ m_Speed = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public int StrRequirement
{
get{ return ( m_StrReq == -1 ? Core.AOS ? AosStrengthReq : OldStrengthReq : m_StrReq ); }
set{ m_StrReq = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public int DexRequirement
{
get{ return ( m_DexReq == -1 ? Core.AOS ? AosDexterityReq : OldDexterityReq : m_DexReq ); }
set{ m_DexReq = value; }
}
[CommandProperty( AccessLevel.GameMaster )]
public int IntRequirement
{
get{ return ( m_IntReq == -1 ? Core.AOS ? AosIntelligenceReq : OldIntelligenceReq : m_IntReq ); }
set{ m_IntReq = value; }
}
[CommandProperty( AccessLevel.GameMaster )]
public WeaponAccuracyLevel AccuracyLevel
{
get
{
return m_AccuracyLevel;
}
set
{
if ( m_AccuracyLevel != value )
{
m_AccuracyLevel = value;
if ( UseSkillMod )
{
if ( m_AccuracyLevel == WeaponAccuracyLevel.Regular )
{
if ( m_SkillMod != null )
m_SkillMod.Remove();
m_SkillMod = null;
}
else if ( m_SkillMod == null && Parent is Mobile )
{
m_SkillMod = new DefaultSkillMod( AccuracySkill, true, (int)m_AccuracyLevel * 5 );
((Mobile)Parent).AddSkillMod( m_SkillMod );
}
else if ( m_SkillMod != null )
{
m_SkillMod.Value = (int)m_AccuracyLevel * 5;
}
}
InvalidateProperties();
}
}
}
#endregion
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 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 += m_AosWeaponAttributes.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 = m_AosWeaponAttributes.LowerStatReq;
CraftResourceInfo info = CraftResources.GetInfo( m_Resource );
if ( info != null )
{
CraftAttributeInfo attrInfo = info.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( typeof( BaseWeapon ) ) )
new ResetEquipTimer( m, duration ).Start();
}
private class ResetEquipTimer : Timer
{
private Mobile m_Mobile;
public ResetEquipTimer( Mobile m, TimeSpan duration ) : base( duration )
{
m_Mobile = m;
}
protected override void OnTick()
{
m_Mobile.EndAction( typeof( BaseWeapon ) );
}
}
public override bool CheckConflictingLayer( Mobile m, Item item, Layer layer )
{
if ( base.CheckConflictingLayer( m, item, layer ) )
return true;
if ( this.Layer == Layer.TwoHanded && layer == Layer.OneHanded )
{
m.SendLocalizedMessage( 500214 ); // You already have something in both hands.
return true;
}
else if ( this.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 )
{
if ( !Ethics.Ethic.CheckTrade( from, to, newOwner, this ) )
return false;
return base.AllowSecureTrade( from, to, newOwner, accepted );
}
public virtual Race RequiredRace { get { return null; } } //On OSI, there are no weapons with race requirements, this is for custom stuff
public override bool CanEquip( Mobile from )
{
if ( !Ethics.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;
}
else if ( from.Dex < DexRequirement )
{
from.SendMessage( "You are not nimble enough to equip that." );
return false;
}
else if ( from.Str < AOS.Scale( StrRequirement, 100 - GetLowerStatReq() ) )
{
from.SendLocalizedMessage( 500213 ); // You are not strong enough to equip that.
return false;
}
else if ( from.Int < IntRequirement )
{
from.SendMessage( "You are not smart enough to equip that." );
return false;
}
else if ( !from.CanBeginAction( typeof( BaseWeapon ) ) )
{
return false;
}
else
{
return base.CanEquip( from );
}
}
public virtual bool UseSkillMod{ get{ return !Core.AOS; } }
public override bool OnEquip( Mobile from )
{
int strBonus = m_AosAttributes.BonusStr;
int dexBonus = m_AosAttributes.BonusDex;
int intBonus = m_AosAttributes.BonusInt;
if ( (strBonus != 0 || dexBonus != 0 || intBonus != 0) )
{
Mobile m = from;
string modName = this.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 = DateTime.Now + GetDelay( from );
if ( UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular )
{
if ( m_SkillMod != null )
m_SkillMod.Remove();
m_SkillMod = new DefaultSkillMod( AccuracySkill, true, (int)m_AccuracyLevel * 5 );
from.AddSkillMod( m_SkillMod );
}
if ( Core.AOS && m_AosWeaponAttributes.MageWeapon != 0 && m_AosWeaponAttributes.MageWeapon != 30 )
{
if ( m_MageMod != null )
m_MageMod.Remove();
m_MageMod = new DefaultSkillMod( SkillName.Magery, true, -30 + m_AosWeaponAttributes.MageWeapon );
from.AddSkillMod( m_MageMod );
}
return true;
}
public override void OnAdded( object parent )
{
base.OnAdded( parent );
if ( parent is Mobile )
{
Mobile from = (Mobile)parent;
if ( Core.AOS )
m_AosSkillBonuses.AddTo( from );
from.CheckStatTimers();
from.Delta( MobileDelta.WeaponDamage );
}
}
public override void OnRemoved( object parent )
{
if ( parent is Mobile )
{
Mobile m = (Mobile)parent;
BaseWeapon weapon = m.Weapon as BaseWeapon;
string modName = this.Serial.ToString();
m.RemoveStatMod( modName + "Str" );
m.RemoveStatMod( modName + "Dex" );
m.RemoveStatMod( modName + "Int" );
if ( weapon != null )
m.NextCombatTime = DateTime.Now + weapon.GetDelay( m );
if ( UseSkillMod && m_SkillMod != null )
{
m_SkillMod.Remove();
m_SkillMod = null;
}
if ( m_MageMod != null )
{
m_MageMod.Remove();
m_MageMod = null;
}
if ( Core.AOS )
m_AosSkillBonuses.Remove();
m.CheckStatTimers();
m.Delta( MobileDelta.WeaponDamage );
}
}
public virtual SkillName GetUsedSkill( Mobile m, bool checkSkillAttrs )
{
SkillName sk;
if ( checkSkillAttrs && m_AosWeaponAttributes.UseBestSkill != 0 )
{
double swrd = m.Skills[SkillName.Swords].Value;
double fenc = m.Skills[SkillName.Fencing].Value;
double mcng = m.Skills[SkillName.Macing].Value;
double val;
sk = SkillName.Swords;
val = swrd;
if ( fenc > val ){ sk = SkillName.Fencing; val = fenc; }
if ( mcng > val ){ sk = SkillName.Macing; val = mcng; }
}
else if ( m_AosWeaponAttributes.MageWeapon != 0 )
{
if ( m.Skills[SkillName.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[SkillName.Wrestling].Value > m.Skills[sk].Value )
sk = SkillName.Wrestling;
}
return sk;
}
public virtual double GetAttackSkillValue( Mobile attacker, Mobile defender )
{
return attacker.Skills[GetUsedSkill( attacker, true )].Value;
}
public virtual double GetDefendSkillValue( Mobile attacker, Mobile defender )
{
return defender.Skills[GetUsedSkill( defender, true )].Value;
}
private static bool CheckAnimal( Mobile m, Type type )
{
return 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];
Skill defSkill = defender.Skills[defWeapon.Skill];
double atkValue = atkWeapon.GetAttackSkillValue( attacker, defender );
double defValue = defWeapon.GetDefendSkillValue( attacker, defender );
//attacker.CheckSkill( atkSkill.SkillName, defValue - 20.0, 120.0 );
//defender.CheckSkill( defSkill.SkillName, atkValue - 20.0, 120.0 );
double ourValue, theirValue;
int bonus = GetHitChanceBonus();
if ( Core.AOS )
{
if ( atkValue <= -20.0 )
atkValue = -19.9;
if ( defValue <= -20.0 )
defValue = -19.9;
// Hit Chance Increase = 45%
int atkChance = AosAttributes.GetValue( attacker, AosAttribute.AttackChance );
if ( atkChance > 45 )
atkChance = 45;
bonus += atkChance;
if ( Spells.Chivalry.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
ourValue = (atkValue + 20.0) * (100 + bonus);
// Defense Chance Increase = 45%
bonus = AosAttributes.GetValue( defender, AosAttribute.DefendChance );
if ( bonus > 45 )
bonus = 45;
if ( Spells.Chivalry.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 ( SkillHandlers.Discordance.GetEffect( attacker, ref discordanceEffect ) )
bonus -= discordanceEffect;
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;
WeaponAbility ability = WeaponAbility.GetCurrentAbility( attacker );
if ( ability != null )
chance *= ability.AccuracyScalar;
SpecialMove move = SpecialMove.GetCurrentMove( attacker );
if ( move != null )
chance *= move.GetAccuracyScalar( attacker );
return attacker.CheckSkill( atkSkill.SkillName, chance );
//return ( chance >= Utility.RandomDouble() );
}
public virtual TimeSpan GetDelay( Mobile m )
{
int speed = this.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 ( Spells.Chivalry.DivineFurySpell.UnderEffect( m ) )
bonus += 10;
// Bonus granted by successful use of Honorable Execution.
bonus += HonorableExecution.GetSwingBonus( m );
if( DualWield.Registry.Contains( m ) )
bonus += ((DualWield.DualWieldTimer)DualWield.Registry[m]).BonusSwingSpeed;
if( Feint.Registry.Contains( m ) )
bonus -= ((Feint.FeintTimer)Feint.Registry[m]).SwingSpeedReduction;
int discordanceEffect = 0;
// Discordance gives a malus of -0/-28% to swing speed.
if ( SkillHandlers.Discordance.GetEffect( m, ref discordanceEffect ) )
bonus -= discordanceEffect;
if ( bonus > 60 )
bonus = 60;
speed = (int)Math.Floor( speed * (bonus + 100.0) / 100.0 );
if ( speed <= 0 )
speed = 1;
int ticks = (int)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) * speed;
int bonus = AosAttributes.GetValue( m, AosAttribute.WeaponSpeed );
if ( Spells.Chivalry.DivineFurySpell.UnderEffect( m ) )
bonus += 10;
int discordanceEffect = 0;
// Discordance gives a malus of -0/-28% to swing speed.
if ( SkillHandlers.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) * speed;
if ( v <= 0 )
v = 1;
delayInSeconds = 15000.0 / v;
}
return TimeSpan.FromSeconds( delayInSeconds );
}
public virtual void OnBeforeSwing( Mobile attacker, Mobile defender )
{
WeaponAbility a = WeaponAbility.GetCurrentAbility( attacker );
if( a != null && !a.OnBeforeSwing( attacker, defender ) )
WeaponAbility.ClearCurrentAbility( attacker );
SpecialMove move = SpecialMove.GetCurrentMove( attacker );
if( move != null && !move.OnBeforeSwing( attacker, defender ) )
SpecialMove.ClearCurrentMove( attacker );
}
public virtual TimeSpan OnSwing( Mobile attacker, Mobile defender )
{
return OnSwing( attacker, defender, 1.0 );
}
public virtual TimeSpan OnSwing( Mobile attacker, Mobile defender, double damageBonus )
{
bool canSwing = true;
if ( Core.AOS )
{
canSwing = ( !attacker.Paralyzed && !attacker.Frozen );
if ( canSwing )
{
Spell sp = attacker.Spell as Spell;
canSwing = ( sp == null || !sp.IsCasting || !sp.BlocksMovement );
}
}
if ( canSwing && attacker.HarmfulCheck( defender ) )
{
attacker.DisruptiveAction();
if ( attacker.NetState != null )
attacker.Send( new Swing( 0, attacker, defender ) );
if ( attacker is BaseCreature )
{
BaseCreature bc = (BaseCreature)attacker;
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 );
}
#region Sounds
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 )
{
return defender.GetHurtSound();
}
public virtual int GetMissAttackSound( Mobile attacker, Mobile defender )
{
if ( attacker.GetAttackSound() == -1 )
return MissSound;
else
return -1;
}
public virtual int GetMissDefendSound( Mobile attacker, Mobile defender )
{
return -1;
}
#endregion
public static bool CheckParry( Mobile defender )
{
if ( defender == null )
return false;
BaseShield shield = defender.FindItemOnLayer( Layer.TwoHanded ) as BaseShield;
double parry = defender.Skills[SkillName.Parry].Value;
double parryNonRacial = defender.Skills[SkillName.Parry].NonRacialValue;
double bushido = defender.Skills[SkillName.Bushido].Value;
if ( shield != null )
{
double chance = (parryNonRacial - bushido) / 400.0; //As per OSI, no negitive effect from the Racial stuffs, ie, 120 bushido and '0' parry with humans
// Parry over 100 grants a 5% bonus.
if ( parry >= 100.0 )
chance += 0.05;
// Evasion grants a 50% bonus.
if ( Evasion.IsEvading( defender ) )
chance *= 1.5;
// Low dexterity lowers the chance.
if ( defender.Dex < 80 )
chance = chance * (20 + defender.Dex) / 100;
return defender.CheckSkill( SkillName.Parry, chance );
}
else if ( !(defender.Weapon is Fists) && !(defender.Weapon is BaseRanged) )
{
BaseWeapon weapon = defender.Weapon as BaseWeapon;
double divisor = (weapon.Layer == Layer.OneHanded) ? 48000.0 : 41140.0;
double 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 50% bonus.
if( Evasion.IsEvading( defender ) )
chance *= 1.5;
// Low dexterity lowers the chance.
if( defender.Dex < 80 )
chance = chance * (20 + defender.Dex) / 100;
if ( chance > aosChance )
return defender.CheckSkill( SkillName.Parry, chance );
else
return (aosChance > Utility.RandomDouble()); // Only skillcheck if wielding a shield & there's no effect from Bushido
}
return false;
}
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 ) )
{
BaseWeapon weapon = defender.Weapon as BaseWeapon;
if ( weapon != null )
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;
if ( shield != null )
{
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;
IWearableDurability armor = armorItem as IWearableDurability;
if ( armor != null )
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 );
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;
IWearableDurability armor = armorItem as IWearableDurability;
if ( armor != null )
damage = armor.OnHit( this, damage );
BaseShield shield = defender.FindItemOnLayer( Layer.TwoHanded ) as BaseShield;
if ( shield != null )
damage = shield.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;
BaseCreature bc = attacker |