diff --git a/data/dfndata/items/gmmenu/spawners.dfn b/data/dfndata/items/gmmenu/spawners.dfn
index 342ebcb4f..a5fc82e11 100644
--- a/data/dfndata/items/gmmenu/spawners.dfn
+++ b/data/dfndata/items/gmmenu/spawners.dfn
@@ -7,6 +7,7 @@ interval=1 5
 visible=1
 decay=0
 movable=2
+script=2205
 }
 
 [orcspawn]
diff --git a/data/dfndata/items/lootlists.dfn b/data/dfndata/items/lootlists.dfn
index 7a62a53fd..0638b0eee 100644
--- a/data/dfndata/items/lootlists.dfn
+++ b/data/dfndata/items/lootlists.dfn
@@ -962,4 +962,53 @@
 100|PaintedPlagueMask
 100|PaintedDaemonMask
 100|PaintedEvilClownMask
+}
+
+// Treasure Map Level 0
+[LOOTLIST TreasureMapLvl0Loot]
+{//approximately 1%
+990|blank
+10|treasuremaplvl0
+}
+
+// Treasure Map Level 1
+[LOOTLIST TreasureMapLvl1Loot]
+{//approximately 1%
+990|blank
+10|treasuremaplvl1
+}
+
+// Treasure Map Level 2
+[LOOTLIST TreasureMapLvl2Loot]
+{//approximately 1%
+990|blank
+10|treasuremaplvl2
+}
+
+// Treasure Map Level 3
+[LOOTLIST TreasureMapLvl3Loot]
+{//approximately 1%
+990|blank
+10|treasuremaplvl3
+}
+
+// Treasure Map Level 4
+[LOOTLIST TreasureMapLvl4Loot]
+{//approximately 1%
+990|blank
+10|treasuremaplvl4
+}
+
+// Treasure Map Level 5
+[LOOTLIST TreasureMapLvl5Loot]
+{//approximately 1%
+990|blank
+10|treasuremaplvl5
+}
+
+// Treasure Map Level 6
+[LOOTLIST TreasureMapLvl6Loot]
+{//approximately 1%
+990|blank
+10|treasuremaplvl6
 }
\ No newline at end of file
diff --git a/data/dfndata/skills/skills.dfn b/data/dfndata/skills/skills.dfn
index b28b32a15..28d129929 100644
--- a/data/dfndata/skills/skills.dfn
+++ b/data/dfndata/skills/skills.dfn
@@ -1206,10 +1206,10 @@ SKILLPOINT=990,5,0
 SKILLPOINT=1000,0,0
 }
 
-// Imbuing
+// Mysticism
 [SKILL 55]
 {
-NAME=IMBUING
+NAME=MYSTICISM
 STR=0
 DEX=0
 INT=0
@@ -1227,10 +1227,10 @@ SKILLPOINT=990,5,0
 SKILLPOINT=1000,0,0
 }
 
-// Mysticism
+// Imbuing
 [SKILL 56]
 {
-NAME=MYSTICISM
+NAME=IMBUING
 STR=0
 DEX=0
 INT=0
diff --git a/data/js/combat/leechstats.js b/data/js/combat/leechstats.js
new file mode 100644
index 000000000..fc1086fdf
--- /dev/null
+++ b/data/js/combat/leechstats.js
@@ -0,0 +1,56 @@
+function onEquip( pEquipper, iEquipped ) 
+{
+	pEquipper.AddScriptTrigger( 7003 );
+}
+
+// Remove script trigger on unequip
+function onUnequip( pUnequipper, iUnequipped )
+{
+	pUnequipper.RemoveScriptTrigger( 7003 );
+}
+
+function onDamageDeal( attacker, damaged, damageValue, damageType ) 
+{
+	// Fetch weapon in main hand or secondary hand
+	var iWeapon = attacker.FindItemLayer( 0x01 );
+	if( !ValidateObject( iWeapon )) 
+	{
+		iWeapon = attacker.FindItemLayer( 0x02 );
+	}
+
+	if( ValidateObject( iWeapon ))
+	{	// Apply leech effects based on weapon properties
+		ApplyLeech( attacker, damaged, damageValue, iWeapon, 'healthLeech', 30 );
+		ApplyLeech( attacker, damaged, damageValue, iWeapon, 'staminaLeech', 100 );
+		ApplyLeech( attacker, damaged, damageValue, iWeapon, 'manaLeech', 40 );
+	}
+
+	return true;
+}
+
+function ApplyLeech( attacker, damaged, damageValue, weapon, leechType, multiplier )
+{	
+	// Get the leech amount for the specified leech type from the weapon
+	var leechPercentVal = weapon[ leechType ];
+	if( leechPercentVal > 0 ) 
+	{   
+		// Calculate the percent of health restored to the attacker
+		var leechAmt = Math.round( damageValue * ( leechPercentVal / 100 ) * ( multiplier/100 ));
+
+		// Apply the leech effect based on the leech type
+		switch( leechType ) 
+		{
+			case 'healthLeech':
+				attacker.Heal( leechAmt );
+				break;
+			case 'staminaLeech':
+				attacker.stamina += leechAmt;
+				break;
+			case 'manaLeech':
+				attacker.mana += leechAmt;
+				break;
+		}
+
+		attacker.SoundEffect( 0x44D, true );
+	}
+}
\ No newline at end of file
diff --git a/data/js/commands/targeting/get.js b/data/js/commands/targeting/get.js
index 2804da034..24ec9a986 100644
--- a/data/js/commands/targeting/get.js
+++ b/data/js/commands/targeting/get.js
@@ -169,6 +169,9 @@ function onCallback0( socket, ourObj )
 	case "SECTIONID":
 		socket.SysMessage( ourObj.sectionID );
 		break;
+	case "SWINGSPEEDINC":
+		socket.SysMessage( swingSpeedIncrease );
+		break;
 	case "SHOULDSAVE":
 		socket.SysMessage( ourObj.shouldSave );
 		break;
@@ -294,30 +297,27 @@ function HandleGetItem( socket, ourItem, uKey )
 	case "DESC":
 		socket.SysMessage( ourItem.desc );
 		break;
-	case "DEF":
-		socket.SysMessage( ourItem.Resist( 1 ));
-		break;
 	case "DEF":
 	case "RESISTARMOR":
-		socket.SysMessage( ourObj.Resist( 1 ));
+		socket.SysMessage( ourItem.Resist( 1 ));
 		break;
 	case "RESISTLIGHT":
-		socket.SysMessage( ourObj.Resist( 2 ));
+		socket.SysMessage( ourItem.Resist( 2 ));
 		break;
 	case "RESISTWATER":
-		socket.SysMessage( ourObj.Resist( 3 ));
+		socket.SysMessage( ourItem.Resist( 3 ));
 		break;
 	case "RESISTCOLD":
-		socket.SysMessage( ourObj.Resist( 4 ));
+		socket.SysMessage( ourItem.Resist( 4 ));
 		break;
 	case "RESISTFIRE":
-		socket.SysMessage( ourObj.Resist( 5 ));
+		socket.SysMessage( ourItem.Resist( 5 ));
 		break;
 	case "RESISTENERGY":
-		socket.SysMessage( ourObj.Resist( 6 ));
+		socket.SysMessage( ourItem.Resist( 6 ));
 		break;
 	case "RESISTPOISON":
-		socket.SysMessage( ourObj.Resist( 7 ));
+		socket.SysMessage( ourItem.Resist( 7 ));
 		break;
 	case "LOWERSTATREQ":
 		socket.SysMessage( ourObj.lowerStatReq );
@@ -601,8 +601,27 @@ function HandleGetChar( socket, ourChar, uKey )
 		break;
 	case "ARMOUR":
 	case "ARMOR":
+	case "RESISTARMOR":
 		socket.SysMessage( ourChar.Resist( 1 ));
 		break;
+	case "RESISTLIGHT":
+		socket.SysMessage( ourChar.Resist( 2 ));
+		break;
+	case "RESISTWATER":
+		socket.SysMessage( ourChar.Resist( 3 ));
+		break;
+	case "RESISTCOLD":
+		socket.SysMessage( ourChar.Resist( 4 ));
+		break;
+	case "RESISTFIRE":
+		socket.SysMessage( ourChar.Resist( 5 ));
+		break;
+	case "RESISTENERGY":
+		socket.SysMessage( ourChar.Resist( 6 ));
+		break;
+	case "RESISTPOISON":
+		socket.SysMessage( ourChar.Resist( 7 ));
+		break;
 	case "MAXHP":
 		socket.SysMessage( ourChar.maxhp );
 		break;
diff --git a/data/js/commands/targeting/set.js b/data/js/commands/targeting/set.js
index 9abe4d36c..366d8bfcf 100644
--- a/data/js/commands/targeting/set.js
+++ b/data/js/commands/targeting/set.js
@@ -173,6 +173,10 @@ function onCallback0( socket, ourObj )
 		ourObj.tempdex = nVal;
 		okMsg( socket );
 		break;
+	case "SWINGSPEEDINC":
+		ourObj.swingSpeedIncrease = nVal;
+		okMsg( socket );
+		break;
 	case "WIPABLE":
 	case "WIPEABLE":
 		ourObj.wipable = ( nVal == 1 );
diff --git a/data/js/item/holidays/addondeedgump.js b/data/js/item/holidays/addondeedgump.js
index 36e94e3e3..1f0851f6e 100644
--- a/data/js/item/holidays/addondeedgump.js
+++ b/data/js/item/holidays/addondeedgump.js
@@ -181,7 +181,7 @@ function CheckForNearbyDoors( myTarget, itemToCheck, pSocket )
 				}
 			}
 
-			if( myTarget.DistanceTo(itemToCheck) <= 2 ) 
+			if( myTarget.DistanceTo( itemToCheck ) <= 2 ) 
 			{
 				return true;
 			}
diff --git a/data/js/item/holidays/candy.js b/data/js/item/holidays/candy.js
index cbe3cdae9..ed007641a 100644
--- a/data/js/item/holidays/candy.js
+++ b/data/js/item/holidays/candy.js
@@ -18,7 +18,6 @@ function onUseChecked(pUser, iUsed)
 		}
 		else 
 		{
-			socket.SysMessage("test 1");
 			if( Acidity <= 30 ) 
 			{
 				pUser.SetTempTag( "Acidity", Acidity += 5 );
@@ -26,7 +25,6 @@ function onUseChecked(pUser, iUsed)
 
 			if ( Toothach == 0)
 			{
-				socket.SysMessage("test 2");
 				pUser.SetTempTag( "toothach", 1 );
 				pUser.StartTimer( 1000, 0, true );
 			}
diff --git a/data/js/item/holidays/halloweenmasks.js b/data/js/item/holidays/halloweenmasks.js
index ac1919dd4..f1f031843 100644
--- a/data/js/item/holidays/halloweenmasks.js
+++ b/data/js/item/holidays/halloweenmasks.js
@@ -3,7 +3,7 @@ function onCreateDFN( objMade, objType )
 	if( objType == 0 )
 	{
 		var maskname = "";
-		switch(objMade.GetTag( "paintedmask" )) 
+		switch( objMade.GetTag( "paintedmask" )) 
 		{
 			case 1: maskname = "A Evil Clown Mask"; break;
 			case 2: maskname = "A Daemon Mask"; break;
diff --git a/data/js/item/holidays/headonaspike.js b/data/js/item/holidays/headonaspike.js
index 8da857603..44b8b6192 100644
--- a/data/js/item/holidays/headonaspike.js
+++ b/data/js/item/holidays/headonaspike.js
@@ -4,7 +4,7 @@ function onUseChecked( pUser, iUsed )
 	var headspike = new Gump;
 	var head = 0;
 
-	switch (iUsed.sectionID)
+	switch( iUsed.sectionID )
 	{
 		case "MrsTroubleMakersHeadOnASpike": head = 30522; break;
 		case "BrutrinsHeadOnASpike": head = 30522; break;
@@ -20,7 +20,7 @@ function onUseChecked( pUser, iUsed )
 		default: head = 30522;
 	}
 
-	headspike.AddGump(100, 100, head);
-	headspike.Send(pUser);
+	headspike.AddGump( 100, 100, head );
+	headspike.Send( pUser );
 	headspike.Free();
 }
\ No newline at end of file
diff --git a/data/js/item/holidays/holidaypottedplant.js b/data/js/item/holidays/holidaypottedplant.js
index 0cc81122f..df0948203 100644
--- a/data/js/item/holidays/holidaypottedplant.js
+++ b/data/js/item/holidays/holidaypottedplant.js
@@ -11,14 +11,14 @@ function onUseChecked( pUser, iUsed )
 	PottedPlantGump( pUser, iUsed );
 }
 
-function PottedPlantGump(pUser, iUsed)
+function PottedPlantGump( pUser, iUsed )
 {
 	var socket = pUser.socket;
 	socket.tempObj = iUsed;
 	var pottedPlant = new Gump;
 
 	pottedPlant.AddPage( 0 );
-	pottedPlant.AddBackground(0, 0, 360, 195, 0xA28);
+	pottedPlant.AddBackground( 0, 0, 360, 195, 0xA28 );
 
 	pottedPlant.AddPage( 1 );
 	pottedPlant.AddText( 45, 15, 0, "Choose a Potted Plant:" );
@@ -35,7 +35,7 @@ function PottedPlantGump(pUser, iUsed)
 	pottedPlant.Free();
 }
 
-function onGumpPress(pSock, pButton, gumpData)
+function onGumpPress( pSock, pButton, gumpData )
 {
 	var pUser = pSock.currentChar;
 	var iUsed = pSock.tempObj;
@@ -48,7 +48,7 @@ function onGumpPress(pSock, pButton, gumpData)
 	}
 
 	var pottedplant = "";
-	if ( pButton >= 1 && pButton <= 5 ) 
+	if( pButton >= 1 && pButton <= 5 ) 
 	{
 		var plantIds = [0x11C8, 0x11C9, 0x11CA, 0x11CB, 0x11CC];
 		pottedplant = "0x" + ( plantIds[pButton - 1] ).toString( 16 );
diff --git a/data/js/item/holidays/pumpkins.js b/data/js/item/holidays/pumpkins.js
index e63df2678..68cb883a8 100644
--- a/data/js/item/holidays/pumpkins.js
+++ b/data/js/item/holidays/pumpkins.js
@@ -16,7 +16,7 @@ function onCreateDFN( objMade, objType )
 
 		if( objMade.id == 0x0C6A || objMade.id == 0x0C6B )
 		{
-			objMade.weight = Math.floor(Math.random() * ( 2500 - 1200 + 1 ) + 1200);
+			objMade.weight = Math.floor( Math.random() * ( 2500 - 1200 + 1 ) + 1200 );
 		} 
 		else if( objMade.id == 0x0C6C )
 		{
@@ -72,22 +72,22 @@ function onUseChecked( pUser, iUsed )
 		// Randomize countdown length, if enabled
 		if( randomizePumpkinCountdown )
 		{
-			iUsed.speed = RandomNumber(iUsed.speed - 1, iUsed.speed + 1);
+			iUsed.speed = RandomNumber( iUsed.speed - 1, iUsed.speed + 1 );
 		}
 		// Item's speed forms the basis of the countdownTime
 		var countdownTime = iUsed.speed * 1000;
 
 		// Start the initial timer that shows the first number over the character/object's head
-		iUsed.StartTimer(200, 1, true);
+		iUsed.StartTimer( 200, 1, true );
 
 		// Start timers with IDs from 2, and count until we reach item's speed + 1
 		var iCount = 2;
-		for (iCount = 2; iCount < (iUsed.speed + 2); iCount++)
+		for( iCount = 2; iCount < ( iUsed.speed + 2 ); iCount++ )
 		{
-			iUsed.StartTimer((iCount - 1) * 1000, iCount, true);
+			iUsed.StartTimer(( iCount - 1) * 1000, iCount, true );
 		}
 
-		socket.CustomTarget(0, GetDictionaryEntry(1348, socket.language)); //Now would be a good time to throw it!
+		socket.CustomTarget( 0, GetDictionaryEntry( 1348, socket.language )); //Now would be a good time to throw it!
 	}
 	return false;
 }
@@ -96,7 +96,7 @@ function onCallback0( socket, ourObj )
 {
 	var mChar = socket.currentChar;
 	var iUsed = socket.tempObj;
-	if ( mChar && mChar.isChar && iUsed && iUsed.isItem )
+	if( mChar && mChar.isChar && iUsed && iUsed.isItem )
 	{
 		var StrangeByte = socket.GetWord( 1 );
 		if( StrangeByte == 0 && ourObj )
@@ -107,7 +107,7 @@ function onCallback0( socket, ourObj )
 				iUsed.container = null;
 				iUsed.Teleport( ourObj );
 			}
-			else 
+			else
 			{
 				socket.SysMessage( GetDictionaryEntry( 1646, socket.language )); // You cannot see that
 
@@ -252,7 +252,7 @@ function ApplyExplosionDamage( timerObj, targetChar )
 			return;
 
 		// Deal damage, and do criminal check for source character!
-		targetChar.Damage(RandomNumber( timerObj.lodamage, timerObj.hidamage ), 5, sourceChar, true );
+		targetChar.Damage( RandomNumber( timerObj.lodamage, timerObj.hidamage ), 5, sourceChar, true );
 
 		// If target is an NPC, make them attack the person who threw the potion!
 		if( targetChar.npc && targetChar.target == null && targetChar.atWar == false )
@@ -299,7 +299,7 @@ function onPickup( iPickedUp, pGrabber, containerObj )
 				else if( iPickedUp.GetTag( "Named" ) == 0 )
 				{
 					iPickedUp.name = pGrabber.name + " Pumpkin";
-					iPickedUp.SetTag("Named", 1);
+					iPickedUp.SetTag( "Named", 1 );
 				}
 			}
 			return true;
diff --git a/data/js/item/holidays/snowpile.js b/data/js/item/holidays/snowpile.js
index c2e92ecc9..58d289745 100644
--- a/data/js/item/holidays/snowpile.js
+++ b/data/js/item/holidays/snowpile.js
@@ -59,7 +59,7 @@ function onCallback0( socket, myTarget )
 		pUser.visible = 0;
 	}
 
-	if (!socket.GetWord(1) && myTarget.isChar && myTarget.socket )
+	if( !socket.GetWord( 1 ) && myTarget.isChar && myTarget.socket )
 	{
 		pUser.DoAction( 0x9 );
 		pUser.SoundEffect( 0x145, true );
@@ -73,10 +73,10 @@ function onCallback0( socket, myTarget )
 	}
 }
 
-function onTimer( pUser, timerID ) 
+function onTimer( pUser, timerID )
 {
 	var socket = pUser.socket;
-	if( pUser.visible == 1 || pUser.visible == 2 ) 
+	if( pUser.visible == 1 || pUser.visible == 2 )
 	{
 		pUser.visible = 0;
 	}
diff --git a/data/js/jse_fileassociations.scp b/data/js/jse_fileassociations.scp
index ceeac4c36..4318369ce 100644
--- a/data/js/jse_fileassociations.scp
+++ b/data/js/jse_fileassociations.scp
@@ -99,6 +99,7 @@
 2202=server/misc/warning_trigger.js
 2203=server/misc/charges_left_tooltip.js
 2204=server/network/0xDF_buffBar.js
+2205=server/misc/spawnergump.js
 
 // Server Data [2500-2749]
 2500=server/data/weapontypes.js
@@ -334,6 +335,7 @@
 // Combat Scripts [7000-7499]
 //-------------------------------------------
 7000=combat/peacemake_effect.js
+7003=combat/leechstats.js
 
 //-------------------------------------------
 // Misc Player Scripts [8000-8499]
diff --git a/data/js/jse_objectassociations.scp b/data/js/jse_objectassociations.scp
index 93f7c41d5..25cce9751 100644
--- a/data/js/jse_objectassociations.scp
+++ b/data/js/jse_objectassociations.scp
@@ -580,6 +580,8 @@
 0x10a4=15007
 
 // Swords
+0x0EC2=5009 //cleaver
+0x0EC3=5009 //cleaver
 0x0EC4=5009 //skinning knife
 0x0EC5=5009 //skinning knife
 0x0F60=5009 //longsword
diff --git a/data/js/npc/ai/vendor_bdo_dispenser.js b/data/js/npc/ai/vendor_bdo_dispenser.js
index 0b5739539..9d069ea22 100644
--- a/data/js/npc/ai/vendor_bdo_dispenser.js
+++ b/data/js/npc/ai/vendor_bdo_dispenser.js
@@ -302,7 +302,7 @@ function onSpeech( myString, pUser, myNPC )
 			{
 				if( CheckBodTimers( pUser, myNPC.GetTag( "bodType" ) ))
 				{
-					if( EraStringToNum( GetServerSetting( "CoreShardEra" )) <= EraStringToNum( "lbr" ))
+					if( EraStringToNum( GetServerSetting( "CoreShardEra" )) >= EraStringToNum( "lbr" ))
 					{
 						myNPC.SetTimer( Timer.MOVETIME, 1000 ); // Pause NPC in their tracks for a second
 						myNPC.TurnToward( pUser );
diff --git a/data/js/server/data/weapontypes.js b/data/js/server/data/weapontypes.js
index 42fe15a2b..0a6940e56 100644
--- a/data/js/server/data/weapontypes.js
+++ b/data/js/server/data/weapontypes.js
@@ -208,6 +208,10 @@ function GetWeaponType( mChar, itemID )
 		case 0x48B3: //gargish axe - SA
 			weaponType = "TWOHND_AXES"; break;
 		// Default Maces
+		case 0x0DF2: // Wand
+		case 0x0DF3: // Wand
+		case 0x0DF4: // Wand
+		case 0x0DF5: // Wand
 		case 0x0FB4: //sledge hammer
 		case 0x0FB5: //sledge hammer
 		case 0x0F5C: //mace
diff --git a/data/js/server/house/houseCommands.js b/data/js/server/house/houseCommands.js
index e27bef044..2c7afd3f3 100644
--- a/data/js/server/house/houseCommands.js
+++ b/data/js/server/house/houseCommands.js
@@ -1522,8 +1522,17 @@ function DemolishHouse( pSocket, iMulti )
 					iMulti.RemoveTrashCont( itemInHouse );
 					itemInHouse.Delete();
 				}
-				else if( itemInHouse.movable == 2 ) // items placed as part of the house itself like forge/anvil in smithy
+				else if( itemInHouse.movable == 2 || itemInHouse.GetTag( "deed" )) // items placed as part of the house itself like forge/anvil in smithy or the addon deed
 				{
+					var addonDeed = itemInHouse.GetTag( "deed" );
+					if( addonDeed )
+					{
+						var newDeed = CreateDFNItem( pSocket, pSocket.currentChar, addonDeed, 1, "ITEM", true );
+						if( newDeed )
+						{
+							pSocket.SysMessage( GetDictionaryEntry( 1970, pSocket.language )); // A deed for the house add-on has been placed in your backpack.
+						}
+					}
 					itemInHouse.Delete();
 				}
 				else if( itemInHouse.isLockedDown )
diff --git a/data/js/server/misc/spawnergump.js b/data/js/server/misc/spawnergump.js
new file mode 100644
index 000000000..449f219a7
--- /dev/null
+++ b/data/js/server/misc/spawnergump.js
@@ -0,0 +1,248 @@
+function onUseChecked( pUser, iUsed )
+{
+	var socket = pUser.socket;
+	var gumpID = 5037 + 0xffff;
+
+	if( socket && iUsed && iUsed.isItem && pUser.isGM )
+	{
+		socket.tempObj = iUsed;
+		socket.CloseGump( gumpID, 0 );
+		spawnerGump( socket, pUser, iUsed );
+	}
+
+	return false;
+}
+
+function spawnerGump( socket, pUser, iUsed )
+{
+	var spawner = new Gump;
+	var powerState = "";
+	var spawnName = "";
+	if( iUsed.sectionalist == true )
+	{
+		powerState = "<basefont color=#00ff00><big>Enabled</big></basefont>";
+		if( iUsed.type == 61 ) 
+		{
+			spawnName = "Item List"
+		}
+		else
+			spawnName = "Npc List"
+	}
+	else 
+	{
+		powerState = "<basefont color=#ff2800><big>Disabled</big></basefont>";
+		if( iUsed.type == 61 ) 
+		{
+			spawnName = "Item"
+		}
+		else
+			spawnName = "Npc"
+	}
+
+	var typeName = "";
+	switch( iUsed.type )
+	{
+		case 61: typeName = "<basefont color=#00ff00><big>Item</big></basefont>"; break
+		case 62: typeName = "<basefont color=#00ff00><big>Npc</big></basefont>"; break
+		case 125: typeName = "<basefont color=#00ff00><big>Escort</big></basefont>"; break
+	}
+
+	var amountLabel = ( iUsed.type != 61 ) ? "<basefont color=#ffffff>Amount</basefont>" : "<basefont color=#ffffff>Spawn Item DFN</basefont>";
+	var applyLabel = "<basefont color=#ffffff>Apply</basefont>";
+	var minLabel = "<basefont color=#ffffff>Min:</basefont>";
+	var maxLabel = "<basefont color=#ffffff>Max:</basefont>";
+
+	spawner.AddPage( 0 );
+
+	spawner.AddBackground( 40, 80, 413, 134, 5054 );
+	spawner.AddCheckerTrans( 40, 80, 413, 134 );
+	spawner.AddPicture( 50, 100, 7956 );
+
+	if( iUsed.type != 61 )
+	{
+		spawner.AddHTMLGump( 310, 100, 178, 22, false, false, amountLabel );
+		spawner.AddHTMLGump( 90, 100, 203, 22, false, false, "<basefont color=#ffffff>Spawn " + spawnName + " DFN</basefont>" );
+
+		spawner.AddHTMLGump( 255, 155, 140, 22, false, false, "<basefont color=#ffffff>Rename</basefont >" );
+
+		spawner.AddButton( 50, 180, 4005, 4007, 1, 0, 1 );
+		spawner.AddHTMLGump( 90, 180, 140, 22, false, false, applyLabel );
+
+		spawner.AddHTMLGump( 80, 152, 140, 22, false, false, minLabel );
+		spawner.AddHTMLGump( 160, 152, 140, 22, false, false, maxLabel );
+
+		spawner.AddCheckbox( 130, 180, 2152, 0, 1 );
+		spawner.AddHTMLGump( 160, 185, 140, 22, false, false, "<basefont color=#ffffff>Spawnlist: " + powerState + "</basefont>" );
+		spawner.AddCheckbox( 300, 180, 2152, 0, 2 );
+		spawner.AddHTMLGump( 330, 185, 140, 22, false, false, "<basefont color=#ffffff>Spawn Type: " + typeName + "</basefont>" );
+		spawner.AddBackground( 80, 120, 201, 28, 5120 );
+		spawner.AddBackground( 305, 120, 134, 28, 5120 );
+		spawner.AddBackground( 105, 150, 50, 25, 5120 );
+		spawner.AddBackground( 190, 150, 50, 25, 5120 );
+		spawner.AddBackground(305, 152, 134, 28, 5120);
+
+		spawner.AddText( 90, 125, 0, iUsed.spawnsection );
+		spawner.AddText( 315, 125, 0, iUsed.amount );
+		spawner.AddText( 110, 155, 0, iUsed.mininterval );
+		spawner.AddText( 195, 155, 0, iUsed.maxinterval );
+		spawner.AddText(310, 152, 0, iUsed.name);
+
+		spawner.AddTextEntry( 90, 125, 178, 20, 1153, 0, 8, iUsed.spawnsection );
+		spawner.AddTextEntry( 315, 125, 115, 20, 1153, 0, 9, iUsed.amount );
+		spawner.AddTextEntry( 110, 155, 40, 20, 1153, 0, 10, iUsed.mininterval );
+		spawner.AddTextEntry( 195, 155, 40, 20, 1153, 0, 11, iUsed.maxinterval );
+		spawner.AddTextEntry(310, 152, 140, 25, 1153, 0, 12, iUsed.name);
+	}
+	else
+	{
+		spawner.AddHTMLGump( 90, 100, 203, 22, false, false, "<basefont color=#ffffff>Spawn " + spawnName + " DFN</basefont>" );
+		spawner.AddHTMLGump( 255, 155, 140, 22, false, false, "<basefont color=#ffffff>Rename</basefont >" );
+		spawner.AddButton( 50, 180, 4005, 4007, 1, 0, 1 );
+		spawner.AddHTMLGump( 90, 180, 140, 22, false, false, applyLabel );
+
+		spawner.AddHTMLGump( 80, 152, 140, 22, false, false, minLabel );
+		spawner.AddHTMLGump( 160, 152, 140, 22, false, false, maxLabel );
+
+		spawner.AddCheckbox( 130, 180, 2152, 0, 1 );
+		spawner.AddHTMLGump( 160, 185, 140, 22, false, false, "<basefont color=#ffffff>Spawnlist: " + powerState + "</basefont>" );
+		spawner.AddCheckbox( 300, 180, 2152, 0, 2 );
+		spawner.AddHTMLGump( 330, 185, 140, 22, false, false, "<basefont color=#ffffff>Spawn Type: " + typeName + "</basefont>" );
+
+		spawner.AddBackground( 80, 120, 201, 28, 5120 );
+		spawner.AddBackground( 105, 150, 50, 25, 5120 );
+		spawner.AddBackground( 190, 150, 50, 25, 5120 );
+		spawner.AddBackground(305, 152, 134, 28, 5120);
+
+		spawner.AddText( 90, 125, 0, iUsed.spawnsection );
+		spawner.AddText( 110, 155, 0, iUsed.mininterval );
+		spawner.AddText( 195, 155, 0, iUsed.maxinterval );
+		spawner.AddText( 310, 152, 0, iUsed.name );
+
+		spawner.AddTextEntry( 90, 125, 178, 20, 1153, 0, 11, iUsed.spawnsection );
+		spawner.AddTextEntry( 110, 155, 40, 20, 1153, 0, 13, iUsed.maxinterval );
+		spawner.AddTextEntry( 195, 155, 40, 20, 1153, 0, 12, iUsed.mininterval );
+		spawner.AddTextEntry( 310, 152, 140, 25, 1153, 0, 10, iUsed.name );
+
+	}
+	spawner.Send( socket );
+	spawner.Free();
+}
+
+function onGumpPress( socket, pButton, gumpData )
+{
+	var pUser = socket.currentChar;
+	var iUsed = socket.tempObj;
+
+	var spawn = gumpData.getEdit( 0 );
+	if( iUsed.type != 61 ) 
+	{
+		var num = gumpData.getEdit( 1 );
+		var min = gumpData.getEdit( 2 );
+		var max = gumpData.getEdit( 3 );
+		var name = gumpData.getEdit( 4 );
+	}
+	else 
+	{
+		var min = gumpData.getEdit( 1 );
+		var max = gumpData.getEdit( 2 );
+		var name = gumpData.getEdit( 3 );
+	}
+	var OtherButton = gumpData.getButton( 0 );
+	switch( pButton ) 
+	{
+		case 0:
+			break;
+		case 1:
+			if( iUsed.type != 61 )
+			{
+				iUsed.spawnsection = spawn;
+				iUsed.amount = num;
+				iUsed.mininterval = min;
+				iUsed.maxinterval = max;
+			}
+			else
+			{
+				iUsed.spawnsection = spawn;
+				iUsed.mininterval = min;
+				iUsed.maxinterval = max;
+			}
+
+			if( name == null || name == " " )
+			{
+				socket.SysMessage(GetDictionaryEntry(9270, socket.language)); // That name is too short, or no name was entered.
+			}
+			else if( name.length > 50 )
+			{
+				pSocket.SysMessage(GetDictionaryEntry(9271, pSocket.language)); // That name is too long. Maximum 50 chars.
+			}
+			else
+			{
+				iUsed.name = name;
+			}
+
+			switch( OtherButton ) 
+			{
+				case 1:
+					if( iUsed.sectionalist == true ) 
+					{
+						pUser.SysMessage( "You have disabled the spawn list. You can now add single DFN." );
+						iUsed.sectionalist = false;
+					}
+					else
+					{
+						pUser.SysMessage( "You have enabled the spawn list. It will now only accept DFN lists." );
+						iUsed.sectionalist = true;
+					}
+					break;
+				case 2:
+					var typeTransitions = {
+						61: { nextType: 62, message: "Changed Type to Npc", resetAmount: false },
+						62: { nextType: 125, message: "Changed Type to Escort", resetAmount: false },
+						125: { nextType: 61, message: "Changed Type to Item", resetAmount: true }
+					};
+
+					var currentTransition = typeTransitions[iUsed.type];
+					if( currentTransition ) 
+					{
+						iUsed.type = currentTransition.nextType;
+						if( currentTransition.resetAmount ) 
+						{
+							iUsed.amount = 0;
+						}
+						pUser.SysMessage( currentTransition.message );
+					}
+					break;
+			}
+			spawnerGump( socket, pUser, iUsed );
+			break;
+	}
+}
+
+function onTooltip( spawner )
+{
+	var typeName = "";
+	switch( spawner.type ) 
+	{
+		case 61: typeName = "<basefont color=#00ff00><big>Item</big></basefont>"; break
+		case 62: typeName = "<basefont color=#00ff00><big>Npc</big></basefont>"; break
+		case 125: typeName = "<basefont color=#00ff00><big>Escort</big></basefont>"; break
+	}
+	var powerState = "";
+	if( spawner.sectionalist == true ) 
+	{
+		powerState = "<basefont color=#00ff00><big>Enabled</big></basefont>";
+	}
+	else
+	{
+		powerState = "<basefont color=#ff2800><big>Disabled</big></basefont>";
+	}
+
+	var tooltipText = "";
+	tooltipText = "Spawn DFN: " + spawner.spawnsection;
+	tooltipText += "\n" + "Spawn Type: " + typeName;
+	tooltipText += "\n" + "Spawn List: " + powerState;
+	tooltipText += "\n" + "Amount: " + "<basefont color=#00ff00>" + spawner.amount + "</big></basefont >";
+	tooltipText += "\n" + "Min Interval: " + "<basefont color=#00ff00>" + spawner.mininterval + "</big></basefont>" + " Max Interval: " + "<basefont color=#00ff00>" + spawner.maxinterval + "</big></basefont>";
+	tooltipText += "\n" + "Region: " + "<basefont color=#00ff00>" + spawner.region.name + "</big></basefont>";
+	return tooltipText;
+}
\ No newline at end of file
diff --git a/data/js/server/network/0xf1_freeshardServerPoll.js b/data/js/server/network/0xf1_freeshardServerPoll.js
index 4b278c240..33e2f1434 100644
--- a/data/js/server/network/0xf1_freeshardServerPoll.js
+++ b/data/js/server/network/0xf1_freeshardServerPoll.js
@@ -1,6 +1,6 @@
 // Handler for Freeshard Server Poll requests from
 // CUO Web (https://play.classicuo.org)
-// Last Updated: 5. September, 2022
+// Last Updated: 3. Decemeber, 2024
 
 function PacketRegistration()
 {
@@ -27,7 +27,18 @@ function onPacketReceive( pSocket, packetNum, subCommand )
 			else
 			{
 				Console.Print( "Freeshard Server Poll Packet detected, responding..." );
-				SendServerPollInfo( pSocket );
+				SendServerPollInfoCompact( pSocket );
+			}
+			break;
+		case 0xFF:
+			if( !GetServerSetting( "FREESHARDSERVERPOLL" ))
+			{
+				Console.Print( "Freeshard Server Poll Packet detected; response disabled via FREESHARDPOLL ini-setting.\n" );
+			}
+			else
+			{
+				Console.Print( "Freeshard Server Poll Packet detected, responding..." );
+				SendServerPollInfoExtended( pSocket );
 			}
 			break;
 		default:
@@ -36,7 +47,7 @@ function onPacketReceive( pSocket, packetNum, subCommand )
 	return;
 }
 
-function SendServerPollInfo( pSocket )
+function SendServerPollInfoCompact( pSocket )
 {
 	var uptime = Math.floor( GetCurrentClock() / 1000 ) - Math.floor( GetStartTime() / 1000 );
 	var totalAccounts = GetAccountCount();
@@ -55,8 +66,31 @@ function SendServerPollInfo( pSocket )
 	toSend.WriteLong( 15, uptime ); // Server Uptime
 	toSend.WriteLong( 19, memoryHigh ); // Max memory usage - no need to send
 	toSend.WriteLong( 23, memoryLow ); // Min memory usage - no need to send
-	pSocket.Send( toSend );
+	pSocket.Send(toSend);
 	toSend.Free();
 	Console.Print( "Done!\n" );
 	Console.Log( "Response sent to Freeshard Server Poll Packet (totalOnline: " + totalOnline + ", upTimeInSeconds: " + uptime );
 }
+
+function SendServerPollInfoExtended( pSocket )
+{
+	var protocolVersion = 2;
+	var shardName = GetServerSetting( "SERVERNAME" );
+	var uptime = Math.floor( GetCurrentClock() / 1000 ) - Math.floor( GetStartTime() / 1000 );
+	var totalOnline = GetPlayerCount();
+	var totalItems = 0;
+	var totalChars = 0;
+	var totalMemory = 0;
+	var statsStr = "UOX3, Name=" + shardName + ", Age=" + Math.round( uptime / 60 / 60 ) + ", Clients=" + totalOnline + ", Items=" + totalItems + ", Chars=" + totalChars + ", Mem=" + totalMemory + "K, Ver=" + protocolVersion;
+	var toSend = new Packet;
+
+	toSend.ReserveSize( statsStr.length + 2 );
+	toSend.WriteByte( 0, 0x53 ); // PacketID
+	toSend.WriteShort( 1, statsStr.length ); // Length
+	toSend.WriteString( 3, statsStr, statsStr.length );
+	toSend.WriteByte( statsStr.length + 1, 0x00 ); // null terminated
+	pSocket.Send( toSend );
+	toSend.Free();
+	Console.Print( "Done!\n" );
+	Console.Log( "Response sent to Freeshard Server Poll Packet (totalOnline: " + totalOnline + ", upTimeInSeconds: " + uptime );
+}
\ No newline at end of file
diff --git a/docs/jsdocs.html b/docs/jsdocs.html
index 8dbe347a8..8665ea36c 100644
--- a/docs/jsdocs.html
+++ b/docs/jsdocs.html
@@ -4018,7 +4018,7 @@ <h4>January 9th, 2022</h4>
 					<div class="text-component">
 						<div class="settingsDiv">
 							<p><span class="hl">Prototype</span></p>
-							<p><em>function onSpellTargetSelect( pCaster, myTarget, spellID )</em></p>
+							<p><em>function onSpellTargetSelect( myTarget, pCaster, spellID )</em></p>
 						</div>
 						<div class="settingsDiv">
 							<p><span class="hl">Purpose</span></p>
@@ -4043,7 +4043,7 @@ <h4>January 9th, 2022</h4>
 						<div class="settingsDiv">
 							<p><span class="hl">Example of usage</span><br>
 <pre><code class="language-javascript">// Script attached to an NPC that's immune to magic, where event returns 2 to reject spell being cast
-function onSpellTargetSelect( pCaster, myTarget, spellID )
+function onSpellTargetSelect( myTarget, pCaster, spellID )
 {
 	var socket = pCaster.socket;
 	if( socket != null )
diff --git a/source/CPacketSend.cpp b/source/CPacketSend.cpp
index 95fe21701..e1e1520be 100644
--- a/source/CPacketSend.cpp
+++ b/source/CPacketSend.cpp
@@ -70,7 +70,7 @@ using namespace std::string_literals;
 //|						BYTE[2] unknown5 (0x0)
 //|						BYTE[4] unknown6 (0x0)
 //|
-//|						Note: Only send once after login. It’s mandatory to send it once.
+//|						Note: Only send once after login. It’s mandatory to send it once.
 //o------------------------------------------------------------------------------------------------o
 void CPCharLocBody::Log( std::ostream &outStream, bool fullHeader )
 {
@@ -1411,7 +1411,7 @@ CPPaperdoll &CPPaperdoll::operator = ( CChar &toCopy )
 //|
 //|					Packet Build
 //|						BYTE cmd
-//|						BYTE type (0x00 – “It starts to rain”, 0x01 – “A fierce storm approaches.”, 0x02 – “It begins to snow”, 0x03 - “A storm is brewing.”, 0xFF – None (turns off sound effects), 0xFE (no effect?? Set temperature?)
+//|						BYTE type (0x00 – “It starts to rain”, 0x01 – “A fierce storm approaches.”, 0x02 – “It begins to snow”, 0x03 - “A storm is brewing.”, 0xFF – None (turns off sound effects), 0xFE (no effect?? Set temperature?)
 //|						BYTE num (number of weather effects on screen)
 //|						BYTE temperature
 //|
@@ -1422,8 +1422,8 @@ CPPaperdoll &CPPaperdoll::operator = ( CChar &toCopy )
 //|					Note: Weather messages are only displayed when weather starts.
 //|					Note: Weather will end automatically after 6 minutes without any weather change packets.
 //|					Note: You can totally end weather (to display a new message) by teleporting.
-//|						I think it’s either the 0x78 or 0x20 messages that reset it, though I
-//|						haven’t checked to be sure (other possibilities, 0x4F or 0x4E)
+//|						I think it’s either the 0x78 or 0x20 messages that reset it, though I
+//|						haven’t checked to be sure (other possibilities, 0x4F or 0x4E)
 //o------------------------------------------------------------------------------------------------o
 void CPWeather::InternalReset( void )
 {
@@ -2043,7 +2043,7 @@ void CPOpenGump::Serial( SERIAL toSet )
 //|						BYTE unknown (0x00)
 //|						BYTE click zLoc
 //|						BYTE[2] model # (if a static tile, 0 if a map/landscape tile)
-//|							Note: the model # shouldn’t be trusted.
+//|							Note: the model # shouldn’t be trusted.
 //o------------------------------------------------------------------------------------------------o
 CPTargetCursor::CPTargetCursor()
 {
@@ -2601,7 +2601,7 @@ void CPStatWindow::TithingPoints( UI32 value )
 //|							0x07 idle
 //|							0x05 another character is online
 //|								"Another character from this account is currently online in this world.
-//|								You must either log in as that character or wait for it to time out.”
+//|								You must either log in as that character or wait for it to time out.”
 //o------------------------------------------------------------------------------------------------o
 void CPIdleWarning::InternalReset( void )
 {
@@ -3107,12 +3107,12 @@ CPMultiPlacementView::CPMultiPlacementView( SERIAL toSet )
 //|						0	neither T2A NOR LBR, equal to not sending it at all,
 //|						1	is T2A, chatbutton,
 //|						2	is LBR without chatbutton,
-//|						3	is LBR with chatbutton…
+//|						3	is LBR with chatbutton…
 //|						8013	LBR + chatbutton + AOS enabled
 //|
 //|						Note1: this message is send immediately after login.
-//|						Note2: on OSI  servers this controls features OSI enables/disables via “upgrade codes.”
-//|						Note3: a 3 doesn’t seem to “hurt” older (NON LBR) clients.
+//|						Note2: on OSI  servers this controls features OSI enables/disables via “upgrade codes.”
+//|						Note3: a 3 doesn’t seem to “hurt” older (NON LBR) clients.
 //o------------------------------------------------------------------------------------------------o
 CPEnableClientFeatures::CPEnableClientFeatures( CSocket *mSock )
 {
@@ -6118,7 +6118,7 @@ void CPObjectInfo::Objects( CItem& mItem, CChar& mChar )
 //|						BYTE[2] Font
 //|						BYTE[4] Language
 //|						BYTE[30] Name
-//|						BYTE[?][2] Msg – Null Terminated (blockSize - 48)
+//|						BYTE[?][2] Msg – Null Terminated (blockSize - 48)
 //|
 //|					The various types of text is as follows:
 //|						0x00 - Normal
@@ -6294,7 +6294,7 @@ void CPUnicodeSpeech::GhostIt( [[maybe_unused]] UI08 method )
 //|						BYTE[2] Font
 //|						BYTE[4] Language
 //|						BYTE[30] Name
-//|						BYTE[?][2] Msg – Null Terminated (blockSize - 48)
+//|						BYTE[?][2] Msg – Null Terminated (blockSize - 48)
 //|
 //|					The various types of text is as follows:
 //|						0x00 - Normal
@@ -6572,7 +6572,7 @@ void CPSecureTrading::Name( const std::string& nameFollowing )
 //o------------------------------------------------------------------------------------------------o
 //| Purpose		-	Handles outgoing packet with server response to all names request
 //o------------------------------------------------------------------------------------------------o
-//|	Notes		-	Packet: 0x98 (All-names “3D”)
+//|	Notes		-	Packet: 0x98 (All-names “3D”)
 //|					Size: Variable
 //|
 //|					Packet Build
@@ -6588,7 +6588,7 @@ void CPSecureTrading::Name( const std::string& nameFollowing )
 //|						Client asks for name of object with ID x.
 //|						Server has to reply with ID + name
 //|						Client automatically knows names of items.
-//|						Hence it only asks only for NPC/Player names nearby, but shows bars of items plus NPC’s.
+//|						Hence it only asks only for NPC/Player names nearby, but shows bars of items plus NPC’s.
 //|
 //|						Client request has 7 bytes, server-reply 37
 //|						Triggered by Crtl + Shift.
@@ -6641,7 +6641,7 @@ void CPAllNames3D::Object( CBaseObject& obj )
 //|								BYTE[var] null terminated line
 //|						Note:
 //|						server side: # of pages equals value given in 0x93/0xd4
-//|						EACH page # given. If empty: # lines: 0 + terminator (=3 0’s)
+//|						EACH page # given. If empty: # lines: 0 + terminator (=3 0’s)
 //|						client side:  # of pages always 1. if 2 pages changed, client generates 2 packets.
 //o------------------------------------------------------------------------------------------------o
 void CPBookPage::IncLength( UI08 amount )
@@ -7009,7 +7009,7 @@ bool CPNewSpellBook::ClientCanReceive( CSocket *mSock )
 //|							BYTE[4]	Serial
 //|							BYTE Damage // how much damage was done ?
 //|
-//|						Note: displays damage above the npc/player’s head.
+//|						Note: displays damage above the npc/player’s head.
 //o------------------------------------------------------------------------------------------------o
 void CPDisplayDamage::InternalReset( void )
 {
@@ -7473,6 +7473,28 @@ void CPToolTip::CopyItemData( CItem& cItem, size_t &totalStringLen, bool addAmou
 		tempEntry.ourText = oldstrutil::number( cItem.GetTempVar( CITV_MOREZ ));
 		FinalizeData( tempEntry, totalStringLen );
 	}
+
+	if( cItem.GetManaLeech() > 0 )
+	{
+		tempEntry.stringNum = 1060427; // hit mana leech ~1_val~%
+		tempEntry.ourText = oldstrutil::number( cItem.GetManaLeech() );
+		FinalizeData( tempEntry, totalStringLen );
+	}
+
+	if( cItem.GetStaminaLeech() > 0 )
+	{
+		tempEntry.stringNum = 1060430; // hit stamina leech ~1_val~%
+		tempEntry.ourText = oldstrutil::number( cItem.GetStaminaLeech() );
+		FinalizeData( tempEntry, totalStringLen );
+	}
+
+	if( cItem.GetHealthLeech() > 0 )
+	{
+		tempEntry.stringNum = 1060422; // hit life leech ~1_val~%
+		tempEntry.ourText = oldstrutil::number( cItem.GetHealthLeech() );
+		FinalizeData( tempEntry, totalStringLen );
+	}
+
 	if( cItem.GetType() == IT_SPELLCHANNELING )
 	{
 		tempEntry.stringNum = 1060482; // spell channeling
@@ -7552,7 +7574,15 @@ void CPToolTip::CopyItemData( CItem& cItem, size_t &totalStringLen, bool addAmou
 			if( cItem.GetSpeed() > 0 )
 			{
 				tempEntry.stringNum = 1061167; // weapon speed ~1_val~
-				tempEntry.ourText = oldstrutil::number( cItem.GetSpeed() );
+				if( cwmWorldState->ServerData()->ExpansionCoreShardEra() >= ER_ML )
+				{
+					R64 wpnSpeedInSeconds = std::round(( 40000.0 / ( 200 * cItem.GetSpeed() ) * 0.5 ) * 10 ) / 10;
+					tempEntry.ourText = oldstrutil::format( "%.1fs", wpnSpeedInSeconds );
+				}
+				else
+				{
+					tempEntry.ourText = oldstrutil::number( cItem.GetSpeed() );
+				}
 				FinalizeData( tempEntry, totalStringLen );
 			}
 
@@ -7665,6 +7695,48 @@ void CPToolTip::CopyItemData( CItem& cItem, size_t &totalStringLen, bool addAmou
 				FinalizeData( tempEntry, totalStringLen );
 			}
 
+			if( cItem.GetSwingSpeedIncrease() > 0 )
+			{
+				tempEntry.stringNum = 1060486; // swing speed increase ~1_val~%
+				tempEntry.ourText = oldstrutil::number( cItem.GetSwingSpeedIncrease() );
+				FinalizeData( tempEntry, totalStringLen );
+			}
+
+      if( cItem.GetHitChance() > 0 )
+			{
+				tempEntry.stringNum = 1060415; // hit chance increase ~1_val~%
+				tempEntry.ourText = oldstrutil::number( cItem.GetHitChance() );
+				FinalizeData( tempEntry, totalStringLen );
+			}
+
+			if( cItem.GetDefenseChance() > 0 )
+			{
+				tempEntry.stringNum = 1060408; // defense chance increase ~1_val~%
+				tempEntry.ourText = oldstrutil::number( cItem.GetDefenseChance() );
+				FinalizeData( tempEntry, totalStringLen );
+			}
+
+			if( cItem.GetHealthBonus() > 0 )
+			{
+				tempEntry.stringNum = 1060431; // hit point increase ~1_val~
+				tempEntry.ourText = oldstrutil::number( cItem.GetHealthBonus() );
+				FinalizeData( tempEntry, totalStringLen );
+			}
+
+			if( cItem.GetStaminaBonus() > 0 )
+			{
+				tempEntry.stringNum = 1060484; // stamina increase ~1_val~
+				tempEntry.ourText = oldstrutil::number( cItem.GetStaminaBonus() );
+				FinalizeData( tempEntry, totalStringLen );
+			}
+
+			if( cItem.GetManaBonus() > 0 )
+			{
+				tempEntry.stringNum = 1060439; // mana increase ~1_val~
+				tempEntry.ourText = oldstrutil::number( cItem.GetManaBonus() );
+				FinalizeData( tempEntry, totalStringLen );
+			}
+
 			const SI16 strReq = ( cItem.GetStrength() * ( 100 - cItem.GetLowerStatReq() )) / 100;
 			const SI16 dexReq = ( cItem.GetDexterity() * ( 100 - cItem.GetLowerStatReq() )) / 100;
 			const SI16 intReq = ( cItem.GetIntelligence() * ( 100 - cItem.GetLowerStatReq() )) / 100;
@@ -8061,9 +8133,9 @@ bool CPSellList::CanSellItems( CChar &mChar, CChar &vendor )
 //|						 BYTE[2] len
 //|						 BYTE subcmd
 //|						 BYTE[ len - 4 ] submessage
-//|							Submessage 0 – Display Bulletin Board
+//|							Submessage 0 – Display Bulletin Board
 //|							BYTE[4] Board serial
-//|							BYTE[22] board name (default is “bulletin board”, the rest nulls)
+//|							BYTE[22] board name (default is “bulletin board”, the rest nulls)
 //|							BYTE[4] unknown/ID?
 //|							BYTE[4] zero (0)
 //o------------------------------------------------------------------------------------------------o
@@ -8143,7 +8215,7 @@ CPOpenMessageBoard::CPOpenMessageBoard( CSocket *mSock )
 //|							BYTE subjectLen
 //|							BYTE[subjectLen] subject (null terminated string)
 //|							BYTE timeLen
-//|							BYTE[timeLen] time (null terminated string with time of posting) (“Day 1 @ 11:28”)
+//|							BYTE[timeLen] time (null terminated string with time of posting) (“Day 1 @ 11:28”)
 //o------------------------------------------------------------------------------------------------o
 //|					Subcommand: 0x2 (Message Summary)
 //|					Size: Variable
@@ -8160,7 +8232,7 @@ CPOpenMessageBoard::CPOpenMessageBoard( CSocket *mSock )
 //|							BYTE subjectLen
 //|							BYTE[subjectLen] subject (null terminated string)
 //|							BYTE timeLen
-//|							BYTE[timeLen] time (null terminated string with time of posting) (“Day 1 @ 11:28”)
+//|							BYTE[timeLen] time (null terminated string with time of posting) (“Day 1 @ 11:28”)
 //|							BYTE[5] Unknown (01 90 03 F7 00)
 //|							BYTE numlines
 //|							For each line:
diff --git a/source/Changelog.txt b/source/Changelog.txt
index 38a14fde0..696b42b02 100644
--- a/source/Changelog.txt
+++ b/source/Changelog.txt
@@ -1,11 +1,72 @@
+21/01/2025 - Dragon Slayer
+	Fixed damage dealt in combat was incorrectly modified while applying defense modifiers. (combat.cpp)
+
+07/12/2024 - Dragon Slayer
+	Updated the packet 0xf1 to reflect the current CUO Web Ping while maintaining backward compatibility with older ping statuses. (0xf1_freeshardServerPoll.js) (Thanks Karasho and Xuri)
+
+12/08/2024 - Dragon Slayer
+	Fixed an issue where Imbuing and Mysticism skills were listed in wrong order in skills.dfn and enums.h
+
+4/07/2024 - Dragon Slayer
+	Fixed Cleaver ID missing in the jse_objectassociations.scp for carving corpses
+
+18/06/2024 - Dragon Slayer
+	Added three new DFN tags for Items:
+		HEALTHLEECH=# 	// It gives an attacker the ability to leech health from his opponent every time he successfully delivers a hit adds it to himself.
+		STAMINALEECH=# 	// It gives an attacker the ability to leech Stamina from his opponent every time he successfully delivers a hit adds it to himself.
+		MANALEECH=# 	// It gives an attacker the ability to leech Mana from his opponent every time he successfully delivers a hit adds it to himself.
+	These are also available as JS Engine object properties: .healthLeech, .staminaLeech and .manaLeech
+	Added leechstats.js file that controls the combat for the properties. (script 7003)
+	To add this script to a weapon only. add in SCRIPT=7003, HEALTHLEECH=# or STAMINALEECH=# or MANALEECH=# it can also be all three on the weapon.
+
+16/06/2024 - Dragon Slayer/Xuri
+	Added new DFN tags for Items and Chars:
+		SPEEDINCREASE=# 		// item and char property that increases base weapon swing speed by the specified percentage
+	These are also available as JS Engine object properties: .speedIncrease
+	Added INI Settings:
+		SWINGSPEEDINCREASECAP=#  	// Max cap for for swing speed increase a char can have.
+	Combat code updated with era-specific weapon swing speed calculations for different eras (LBR or earlier/AoS/ML onwards).
+        Note that speeds are still defined with flat values in DFNs regardless of era, but for ML and beyond speed
+ 	will be displayed as swing delay in seconds in item tooltip.
+
+14/06/2024 - Dragon Slayer
+	Added two new DFN tags for Items:
+		HITCHANCE=# 		// Increases the player's chance to hit a target with wrestling, melee and ranged weapons.
+		DEFENSECHANCE=# 	// Increases the wearer's chance that his opponents' swings (or arrows/bolts) will miss.
+	These are also available as JS Engine object properties: .hitChance, .defenseChance
+
+13/06/2024 - Dragon Slayer
+	Added three More AOS Props
+	-HEALTHBONUS=#
+	-MANABONUS=#
+	-STAMINABONUS=#
+	Add this properties to any weapon/armor/jewlery will give the player more hp/mana/stam why its equiped. depending on number you add with it
+	These are also available as JS Engine object properties: .healthBonus, .staminaBonus, .manaBonus
+
+6/06/2024 - Dragon Slayer
+	Fixed Accepting bods, When the expansion is to to lbr or later.
+
+29/05/2024 - Dragon Slayer
+	House add-on deeds are now returned when an add-on is present in the house on demolish.
+
+27/05/2024 - Dragon Slayer
+	Added Missing Wand ID's to combat weapon type in core and in js.
+
 13/05/2024 - Dragon Slayer
 	Added New Shield Type 107 so shield ID's no longer have to be in hard code for shields to work properly
 
+11/05/2024 - Dragon Slayer
+	Updated 'get command (js/commands/targeting/get.js) to use correct object reference when getting resist values for items, and added support for getting resist values for chars
+
 09/05/2024 - Dragon Slayer
 	Added ArtifactRarity AOS Property for items
 	-ARTIFACTRARITY=#
 	-Artifact Rarity is an item property that is visible on some artifacts and meant to give players an idea of how rare the item is. Items with rarity 1 are supposed to be common while rarity 12 are extremely scarce.
 
+5/05/2024 - Dragon Slayer
+	Added Spawner Gump and attached to the base_spawner, just another option for making editing spawners without using commands. (js spawnergump)
+	-Just double click any spawner you create from the addmenu or add from spawners.dfn file, gump will appear if you create a spawner with commands you would have to attach the script directly to it.
+
 1/05/2024 - Dragon Slayer/Xuri
 	Fixed AutoUnequipAttempt function in clumsy.js, createfood.js level1target.js, will no longer fail on casting and return to hardcode.
 	Fixed createfood to check for reagents on cast.
diff --git a/source/SEFunctions.cpp b/source/SEFunctions.cpp
index 1700d8e55..6ec92ec01 100644
--- a/source/SEFunctions.cpp
+++ b/source/SEFunctions.cpp
@@ -5086,6 +5086,9 @@ JSBool SE_GetServerSetting( JSContext *cx, [[maybe_unused]] JSObject *obj, uintN
 			case 349:	 // LOOTDECAYSWITHPLAYERCORPSE
 				*rval = BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->NpcCorpseLootDecay() );
 				break;
+			case 353:	// SWINGSPEEDINCREASECAP
+				*rval = INT_TO_JSVAL( static_cast<SI16>( cwmWorldState->ServerData()->SwingSpeedIncreaseCap() ));
+				break;
 			default:
 				ScriptError( cx, "GetServerSetting: Invalid server setting name provided" );
 				return false;
diff --git a/source/UOXJSPropertyEnums.h b/source/UOXJSPropertyEnums.h
index 16ca81a20..874440fb4 100644
--- a/source/UOXJSPropertyEnums.h
+++ b/source/UOXJSPropertyEnums.h
@@ -339,6 +339,9 @@ enum CC_Properties
 	CCP_SPAWNSERIAL,
 	CCP_SPATTACK,
 	CCP_SPDELAY,
+	CCP_SWINGSPEEDINCREASE,
+	CCP_HITCHANCE,
+	CCP_DEFENSECHANCE,
 	CCP_AITYPE,
 	CCP_SPLIT,
 	CCP_SPLITCHANCE,
@@ -462,6 +465,9 @@ enum CI_Properties
 	CIP_DAMAGEPOISON,
 	CIP_DAMAGERAIN,
 	CIP_DAMAGESNOW,
+	CIP_HITCHANCE,
+	CIP_DEFENSECHANCE,
+
 	CIP_ARTIFACTRARITY,
 	CIP_NAME2,
 	CIP_ISITEM,
@@ -497,7 +503,9 @@ enum CI_Properties
 	CIP_SECTIONALIST,
 	CIP_MININTERVAL,
 	CIP_MAXINTERVAL,
-
+	CIP_HEALTHLEECH,
+	CIP_STAMINALEECH,
+	CIP_MANALEECH,
 	CIP_ISNEWBIE,
 	CIP_ISDISPELLABLE,
 	CIP_MADEWITH,
@@ -518,6 +526,10 @@ enum CI_Properties
 	CIP_ISCONTTYPE,
 	CIP_CARVESECTION,
 	CIP_SPEED,
+	CIP_SWINGSPEEDINCREASE,
+	CIP_HEALTHBONUS,
+	CIP_STAMINABONUS,
+	CIP_MANABONUS,
 	CIP_MULTI,
 	CIP_AMMOID,
 	CIP_AMMOHUE,
@@ -535,7 +547,6 @@ enum CI_Properties
 	CIP_ISITEMHELD,
 	CIP_SECTIONID,
 	CIP_STEALABLE,
-
 	CIP_LOCKDDOWNS,
 	CIP_MAXLOCKDOWNS,
 	CIP_TRASHCONTAINERS,
diff --git a/source/UOXJSPropertyFuncs.cpp b/source/UOXJSPropertyFuncs.cpp
index bb4ab0682..9c1dc93f1 100644
--- a/source/UOXJSPropertyFuncs.cpp
+++ b/source/UOXJSPropertyFuncs.cpp
@@ -675,9 +675,19 @@ JSBool CItemProps_getProperty( JSContext *cx, JSObject *obj, jsval id, jsval *vp
 			case CIP_DAMAGEPOISON:		*vp = BOOLEAN_TO_JSVAL( gPriv->GetWeatherDamage( POISON ));	break;
 			case CIP_DAMAGERAIN:		*vp = BOOLEAN_TO_JSVAL( gPriv->GetWeatherDamage( RAIN ));	break;
 			case CIP_DAMAGESNOW:		*vp = BOOLEAN_TO_JSVAL( gPriv->GetWeatherDamage( SNOW ));	break;
+			case CIP_SWINGSPEEDINCREASE:	*vp = INT_TO_JSVAL( gPriv->GetSwingSpeedIncrease() );			break;
 			case CIP_SPEED:			*vp = INT_TO_JSVAL( gPriv->GetSpeed() );			break;
 			case CIP_LOWERSTATREQ:		*vp = INT_TO_JSVAL( gPriv->GetLowerStatReq() );			break;
+			case CIP_HEALTHLEECH:	*vp = INT_TO_JSVAL( gPriv->GetHealthLeech() );			break;
+			case CIP_STAMINALEECH:	*vp = INT_TO_JSVAL( gPriv->GetStaminaLeech() );			break;
+			case CIP_MANALEECH:		*vp = INT_TO_JSVAL( gPriv->GetManaLeech() );			break;
+			case CIP_HITCHANCE:	*vp = INT_TO_JSVAL( gPriv->GetHitChance() );			break;
+			case CIP_DEFENSECHANCE:	*vp = INT_TO_JSVAL( gPriv->GetDefenseChance() );			break;
+			case CIP_HEALTHBONUS:		*vp = INT_TO_JSVAL( gPriv->GetHealthBonus() );			break;
+			case CIP_STAMINABONUS:		*vp = INT_TO_JSVAL( gPriv->GetStaminaBonus() );			break;
+			case CIP_MANABONUS:		*vp = INT_TO_JSVAL( gPriv->GetManaBonus() );			break;
 			case CIP_ARTIFACTRARITY:		*vp = INT_TO_JSVAL( gPriv->GetArtifactRarity() );			break;
+
 			case CIP_NAME2:
 				tString = JS_NewStringCopyZ( cx, gPriv->GetName2().c_str() );
 				*vp = STRING_TO_JSVAL( tString );
@@ -1324,7 +1334,17 @@ JSBool CItemProps_setProperty( JSContext *cx, JSObject *obj, jsval id, jsval *vp
 			case CIP_DAMAGESNOW:	gPriv->SetWeatherDamage( SNOW, encaps.toBool() );			break;
 			case CIP_SPEED:			gPriv->SetSpeed( static_cast<UI08>( encaps.toInt() ));		break;
 			case CIP_LOWERSTATREQ:	gPriv->SetLowerStatReq( static_cast<SI16>( encaps.toInt() ));	break;
+			case CIP_SWINGSPEEDINCREASE:	gPriv->SetSwingSpeedIncrease( static_cast<SI16>( encaps.toInt() ));	break;
+			case CIP_HEALTHLEECH:	gPriv->SetHealthLeech( static_cast<SI16>( encaps.toInt() ));	break;
+			case CIP_STAMINALEECH:	gPriv->SetStaminaLeech( static_cast<SI16>( encaps.toInt() ));	break;
+			case CIP_MANALEECH:		gPriv->SetManaLeech( static_cast<SI16>( encaps.toInt() ));	break;
+			case CIP_HITCHANCE:	gPriv->SetHitChance( static_cast<SI16>( encaps.toInt() ));	break;
+			case CIP_DEFENSECHANCE:	gPriv->SetDefenseChance( static_cast<SI16>( encaps.toInt() ));	break;
+			case CIP_HEALTHBONUS:		gPriv->SetHealthBonus( static_cast<SI16>( encaps.toInt() ));	break;
+			case CIP_STAMINABONUS:		gPriv->SetStaminaBonus( static_cast<SI16>( encaps.toInt() ));	break;
+			case CIP_MANABONUS:		gPriv->SetManaBonus( static_cast<SI16>( encaps.toInt() ));	break;
 			case CIP_ARTIFACTRARITY:	gPriv->SetArtifactRarity( static_cast<SI16>( encaps.toInt() ));	break;
+
 			case CIP_NAME2:			gPriv->SetName2( encaps.toString() );						break;
 			case CIP_RACE:			gPriv->SetRace( static_cast<RACEID>( encaps.toInt() ));		break;
 			case CIP_MAXHP:			gPriv->SetMaxHP( static_cast<SI16>( encaps.toInt() ));		break;
@@ -1998,6 +2018,9 @@ JSBool CCharacterProps_getProperty( JSContext *cx, JSObject *obj, jsval id, jsva
 			case CCP_HOUSEICONS:	*vp = BOOLEAN_TO_JSVAL( gPriv->ViewHouseAsIcon() );			break;
 			case CCP_SPATTACK:		*vp = INT_TO_JSVAL( gPriv->GetSpAttack() );					break;
 			case CCP_SPDELAY:		*vp = INT_TO_JSVAL( gPriv->GetSpDelay() );					break;
+			case CCP_SWINGSPEEDINCREASE:	*vp = INT_TO_JSVAL( gPriv->GetSwingSpeedIncrease() );		break;
+			case CCP_HITCHANCE:		*vp = INT_TO_JSVAL( gPriv->GetHitChance() );				break;
+			case CCP_DEFENSECHANCE:	*vp = INT_TO_JSVAL( gPriv->GetDefenseChance() );			break;
 			case CCP_AITYPE:		*vp = INT_TO_JSVAL( gPriv->GetNpcAiType() );				break;
 			case CCP_SPLIT:			*vp = INT_TO_JSVAL( gPriv->GetSplit() );					break;
 			case CCP_SPLITCHANCE:	*vp = INT_TO_JSVAL( gPriv->GetSplitChance() );				break;
@@ -2503,6 +2526,9 @@ JSBool CCharacterProps_setProperty( JSContext *cx, JSObject *obj, jsval id, jsva
 			case CCP_HOUSEICONS:	gPriv->SetViewHouseAsIcon( encaps.toBool() );				break;
 			case CCP_SPATTACK:		gPriv->SetSpAttack( static_cast<SI16>( encaps.toInt() ));	break;
 			case CCP_SPDELAY:		gPriv->SetSpDelay( static_cast<SI08>( encaps.toInt() ));	break;
+			case CCP_SWINGSPEEDINCREASE:	gPriv->SetSwingSpeedIncrease( static_cast<SI16>( encaps.toInt() ));		break;
+			case CCP_HITCHANCE:		gPriv->SetHitChance( static_cast<SI16>( encaps.toInt() ));	break;
+			case CCP_DEFENSECHANCE:	gPriv->SetDefenseChance( static_cast<SI16>( encaps.toInt() ));	break;
 			case CCP_AITYPE:		gPriv->SetNPCAiType( static_cast<SI16>( encaps.toInt() ));	break;
 			case CCP_SPLIT:			gPriv->SetSplit( static_cast<UI08>( encaps.toInt() ));		break;
 			case CCP_SPLITCHANCE:	gPriv->SetSplitChance( static_cast<UI08>( encaps.toInt() ));break;
diff --git a/source/UOXJSPropertySpecs.h b/source/UOXJSPropertySpecs.h
index 9ef3206d8..620b4c558 100644
--- a/source/UOXJSPropertySpecs.h
+++ b/source/UOXJSPropertySpecs.h
@@ -357,6 +357,9 @@ inline JSPropertySpec CCharacterProps[] =
 	{ "houseicons",		CCP_HOUSEICONS,		JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "spattack",		CCP_SPATTACK,		JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "spdelay",		CCP_SPDELAY,		JSPROP_ENUMANDPERM, nullptr, nullptr },
+	{ "swingSpeedIncrease",	CCP_SWINGSPEEDINCREASE,	JSPROP_ENUMANDPERM, nullptr, nullptr },
+	{ "hitChance",		CCP_HITCHANCE,		JSPROP_ENUMANDPERM, nullptr, nullptr },
+	{ "defenseChance",	CCP_DEFENSECHANCE,	JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "aitype",			CCP_AITYPE,			JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "split",			CCP_SPLIT,			JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "splitchance",	CCP_SPLITCHANCE,	JSPROP_ENUMANDPERM, nullptr, nullptr },
@@ -536,7 +539,20 @@ inline JSPropertySpec CItemProps[] =
 	{ "ammoFXHue",		CIP_AMMOFXHUE,		JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "ammoFXRender",	CIP_AMMOFXRENDER,	JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "speed",			CIP_SPEED,			JSPROP_ENUMANDPERM, nullptr, nullptr },
+	{ "swingSpeedIncrease",		CIP_SWINGSPEEDINCREASE ,		JSPROP_ENUMANDPERM, nullptr, nullptr },
+
+	{ "healthLeech",	CIP_HEALTHLEECH,	JSPROP_ENUMANDPERM, nullptr, nullptr },
+	{ "staminaLeech",	CIP_STAMINALEECH,	JSPROP_ENUMANDPERM, nullptr, nullptr },
+	{ "manaLeech",		CIP_MANALEECH,		JSPROP_ENUMANDPERM, nullptr, nullptr },
+
+	{ "hitChance",		CIP_HITCHANCE,		JSPROP_ENUMANDPERM, nullptr, nullptr },
+	{ "defenseChance",	CIP_DEFENSECHANCE,		JSPROP_ENUMANDPERM, nullptr, nullptr },
+
+	{ "healthBonus",	CIP_HEALTHBONUS,	JSPROP_ENUMANDPERM, nullptr, nullptr },
+	{ "staminaBonus",	CIP_STAMINABONUS,	JSPROP_ENUMANDPERM, nullptr, nullptr },
+	{ "manaBonus",		CIP_MANABONUS,		JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "artifactRarity",	CIP_ARTIFACTRARITY,	JSPROP_ENUMANDPERM, nullptr, nullptr },
+
 	{ "multi",			CIP_MULTI,			JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "maxRange",		CIP_MAXRANGE,		JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "baseRange",		CIP_BASERANGE,		JSPROP_ENUMANDPERM, nullptr, nullptr },
@@ -677,8 +693,8 @@ inline JSPropertySpec CSkillsProps[] =
 	{ "bushido",			BUSHIDO,			JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "ninjitsu",			NINJITSU,			JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "spellweaving",		SPELLWEAVING,		JSPROP_ENUMANDPERM, nullptr, nullptr },
-	{ "imbuing",			IMBUING,			JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "mysticism",			MYSTICISM,			JSPROP_ENUMANDPERM, nullptr, nullptr },
+	{ "imbuing",			IMBUING,			JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "throwing",			THROWING,			JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ "allskills",			ALLSKILLS,			JSPROP_ENUMANDPERM, nullptr, nullptr },
 	{ nullptr,				static_cast<SI08>(0),			static_cast<UI08>(0), nullptr, nullptr }
diff --git a/source/cBaseObject.cpp b/source/cBaseObject.cpp
index 506c247ac..027ba2bc6 100644
--- a/source/cBaseObject.cpp
+++ b/source/cBaseObject.cpp
@@ -94,6 +94,17 @@ const SI16			DEFBASE_KILLS		= 0;
 const UI16			DEFBASE_RESIST 		= 0;
 const bool			DEFBASE_NAMEREQUESTACTIVE = 0;
 const ExpansionRuleset	DEFBASE_ORIGIN	= ER_UO;
+const SI16			DEFBASE_SWINGSPEEDINCREASE = 0;
+const SI16			DEFBASE_HEALTHLEECH = 0;
+const SI16			DEFBASE_STAMINALEECH = 0;
+const SI16			DEFBASE_MANALEECH = 0;
+
+const SI16			DEFBASE_HITCHANCE = 0;
+const SI16			DEFBASE_DEFENSECHANCE = 0;
+
+const SI16			DEFBASE_HEALTHBONUS = 0;
+const SI16			DEFBASE_STAMINABONOS = 0;
+const SI16			DEFBASE_MANABONUS = 0;
 
 //o------------------------------------------------------------------------------------------------o
 //|	Function	-	CBaseObject constructor
@@ -110,7 +121,9 @@ loDamage( DEFBASE_LODAMAGE ), weight( DEFBASE_WEIGHT ),
 mana( DEFBASE_MANA ), stamina( DEFBASE_STAMINA ), scriptTrig( DEFBASE_SCPTRIG ), st2( DEFBASE_STR2 ), dx2( DEFBASE_DEX2 ),
 in2( DEFBASE_INT2 ), FilePosition( DEFBASE_FP ),
 poisoned( DEFBASE_POISONED ), carve( DEFBASE_CARVE ), oldLocX( 0 ), oldLocY( 0 ), oldLocZ( 0 ), oldTargLocX( 0 ), oldTargLocY( 0 ),
-fame( DEFBASE_FAME ), karma( DEFBASE_KARMA ), kills( DEFBASE_KILLS ), subRegion( DEFBASE_SUBREGION ), nameRequestActive( DEFBASE_NAMEREQUESTACTIVE ), origin( DEFBASE_ORIGIN )
+fame( DEFBASE_FAME ), karma( DEFBASE_KARMA ), kills( DEFBASE_KILLS ), subRegion( DEFBASE_SUBREGION ), nameRequestActive( DEFBASE_NAMEREQUESTACTIVE ), origin( DEFBASE_ORIGIN ),
+healthBonus( DEFBASE_HEALTHBONUS ),staminaBonus( DEFBASE_STAMINABONOS ), manaBonus( DEFBASE_MANABONUS ), hitChance( DEFBASE_HITCHANCE ), defenseChance( DEFBASE_DEFENSECHANCE ),
+healthLeech( DEFBASE_HEALTHLEECH ), staminaLeech( DEFBASE_STAMINALEECH ), manaLeech( DEFBASE_MANALEECH ), swingSpeedIncrease( DEFBASE_SWINGSPEEDINCREASE )
 {
 	multis = nullptr;
 	tempMulti = INVALIDSERIAL;
@@ -793,6 +806,7 @@ bool CBaseObject::DumpBody( std::ostream &outStream ) const
 	outStream << "Intelligence=" + std::to_string( intelligence ) + "," + std::to_string( temp_in2 ) + newLine;
 	outStream << "Strength=" + std::to_string( strength ) + "," + std::to_string( temp_st2 ) + newLine;
 	outStream << "HitPoints=" + std::to_string( hitpoints ) + newLine;
+	outStream << "SwingSpeedInc=" + std::to_string( GetSwingSpeedIncrease() ) + newLine;
 	outStream << "Race=" + std::to_string( race ) + newLine;
 	outStream << "Visible=" + std::to_string( visible ) + newLine;
 	outStream << "Disabled=" << ( IsDisabled() ? "1" : "0" ) << newLine;
@@ -1036,6 +1050,46 @@ void CBaseObject::IncHP( SI16 amtToChange )
 	SetHP( hitpoints + amtToChange );
 }
 
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CBaseObject::GetHitChance()
+//|					CBaseObject::SetHitChance()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Gets/Sets the Defense Chance of the Item(s) Equiped or Character
+//o------------------------------------------------------------------------------------------------o
+SI16 CBaseObject::GetHitChance( void ) const
+{
+	return hitChance;
+}
+void CBaseObject::SetHitChance( SI16 newValue )
+{
+	hitChance = newValue;
+
+	if( CanBeObjType( OT_ITEM ))
+	{
+		( static_cast<CItem *>( this ))->UpdateRegion();
+	}
+}
+
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CBaseObject::GetDefenseChance()
+//|					CBaseObject::SetDefenseChance()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Gets/Sets the Defense Chance of the Item(s) Equiped or Character
+//o------------------------------------------------------------------------------------------------o
+SI16 CBaseObject::GetDefenseChance( void ) const
+{
+	return defenseChance;
+}
+void CBaseObject::SetDefenseChance( SI16 newValue )
+{
+	defenseChance = newValue;
+
+	if( CanBeObjType( OT_ITEM ))
+	{
+		( static_cast<CItem *>( this ))->UpdateRegion();
+	}
+}
+
 //o------------------------------------------------------------------------------------------------o
 //|	Function	-	CBaseObject::GetDir()
 //|					CBaseObject::SetDir()
@@ -1568,6 +1622,27 @@ Point3_st CBaseObject::GetLocation( void ) const
 	return Point3_st( x, y, z );
 }
 
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CBaseObject::GetSwingSpeedIncrease()
+//|					CBaseObject::SetSwingSpeedBonus()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Gets/Sets the item's Swing Speed Bonus property (in percentage), which 
+//|					adjusts the base swing speed of the equipped weapon, or characters
+//o------------------------------------------------------------------------------------------------o
+SI16 CBaseObject::GetSwingSpeedIncrease( void ) const
+{
+	return swingSpeedIncrease;
+}
+void CBaseObject::SetSwingSpeedIncrease( SI16 newValue )
+{
+	swingSpeedIncrease = newValue;
+
+	if( CanBeObjType( OT_ITEM ))
+	{
+		( static_cast<CItem *>( this ))->UpdateRegion();
+	}
+}
+
 //o------------------------------------------------------------------------------------------------o
 //|	Function	-	CBaseObject::GetStrength2()
 //|					CBaseObject::SetStrength2()
@@ -1631,6 +1706,126 @@ void CBaseObject::SetIntelligence2( SI16 nVal )
 	}
 }
 
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CBaseObject::GetHealthLeech()
+//|					CBaseObject::SetHealthLeech()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Gets/Sets the Health Leech
+//o------------------------------------------------------------------------------------------------o
+SI16 CBaseObject::GetHealthLeech( void ) const
+{
+	return healthLeech;
+}
+void CBaseObject::SetHealthLeech( SI16 nVal )
+{
+	healthLeech = nVal;
+
+	if( CanBeObjType( OT_ITEM ))
+	{
+		( static_cast<CItem *>( this ))->UpdateRegion();
+	}
+}
+
+//|	Function	-	CBaseObject::GetHealthBonus()
+//|					CBaseObject::SetHealthBonus()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Gets/Sets the health max var associated with the object. For chars, it's the
+//|					bonuses (via armour and such)
+//o------------------------------------------------------------------------------------------------o
+SI16 CBaseObject::GetHealthBonus( void ) const
+{
+	return healthBonus;
+}
+void CBaseObject::SetHealthBonus( SI16 nVal )
+{
+	healthBonus = nVal;
+
+	if( CanBeObjType( OT_ITEM ))
+	{
+		( static_cast<CItem *>( this ))->UpdateRegion();
+	}
+}
+
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CBaseObject::GetStaminaLeech()
+//|					CBaseObject::SetStaminaLeech()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Gets/Sets the Stamina Leech
+//o------------------------------------------------------------------------------------------------o
+SI16 CBaseObject::GetStaminaLeech( void ) const
+{
+	return staminaLeech;
+}
+void CBaseObject::SetStaminaLeech( SI16 nVal )
+{
+	staminaLeech = nVal;
+
+	if( CanBeObjType( OT_ITEM ))
+	{
+		( static_cast<CItem *>( this ))->UpdateRegion();
+	}
+}
+
+//|	Function	-	CBaseObject::GetStaminaBonus()
+//|					CBaseObject::SetStaminaBonus()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Gets/Sets the stamina max var associated with the object. For chars, it's the
+//|					bonuses (via armour and such)
+//o------------------------------------------------------------------------------------------------o
+SI16 CBaseObject::GetStaminaBonus( void ) const
+{
+	return staminaBonus;
+}
+void CBaseObject::SetStaminaBonus( SI16 nVal )
+{
+	staminaBonus = nVal;
+
+	if( CanBeObjType( OT_ITEM ))
+	{
+		( static_cast<CItem *>( this ))->UpdateRegion();
+	}
+}
+
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CBaseObject::GetManaLeech()
+//|					CBaseObject::SetManaLeech()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Gets/Sets the Mana Leech
+//o------------------------------------------------------------------------------------------------o
+SI16 CBaseObject::GetManaLeech( void ) const
+{
+	return manaLeech;
+}
+void CBaseObject::SetManaLeech( SI16 nVal )
+{
+	manaLeech = nVal;
+
+	if( CanBeObjType( OT_ITEM ))
+	{
+		( static_cast<CItem *>( this ))->UpdateRegion();
+	}
+}
+
+//|	Function	-	CBaseObject::GetManaBonus()
+//|					CBaseObject::SetManaBonus()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Gets/Sets the Mana max var associated with the object. For chars, it's the
+//|					bonuses (via armour and such)
+//o------------------------------------------------------------------------------------------------o
+SI16 CBaseObject::GetManaBonus( void ) const
+{
+	return manaBonus;
+}
+void CBaseObject::SetManaBonus( SI16 nVal )
+{
+	manaBonus = nVal;
+
+	if( CanBeObjType( OT_ITEM ))
+	{
+		( static_cast<CItem *>( this ))->UpdateRegion();
+	}
+}
+
 //o------------------------------------------------------------------------------------------------o
 //|	Function	-	CBaseObject::IncStrength()
 //o------------------------------------------------------------------------------------------------o
@@ -1661,6 +1856,65 @@ void CBaseObject::IncIntelligence( SI16 toInc )
 	SetIntelligence( intelligence + toInc );
 }
 
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CBaseObject::IncSwingSpeedIncrease()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Increments the object's swing speed bonus value
+//o------------------------------------------------------------------------------------------------o
+void CBaseObject::IncSwingSpeedIncrease( SI16 toInc )
+{
+	SetSwingSpeedIncrease( swingSpeedIncrease + toInc );
+}
+
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CBaseObject::IncHealthLeech()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Increments the object's Health Leech Points value
+//o------------------------------------------------------------------------------------------------o
+void CBaseObject::IncHealthLeech( SI16 toInc )
+{
+	SetHealthLeech( healthLeech + toInc );
+}
+
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CBaseObject::IncStaminaLeech()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Increments the object's Stamina Leech Points value
+//o------------------------------------------------------------------------------------------------o
+void CBaseObject::IncStaminaLeech( SI16 toInc )
+{
+	SetStaminaLeech( staminaLeech + toInc );
+}
+
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CBaseObject::IncManaLeech()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Increments the object's Mana Leech Points value
+//o------------------------------------------------------------------------------------------------o
+void CBaseObject::IncManaLeech( SI16 toInc )
+{
+	SetManaLeech( manaLeech + toInc );
+}
+
+//|	Function	-	CBaseObject::IncHitChance()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Increments the object's Hit Chance value
+//o------------------------------------------------------------------------------------------------o
+void CBaseObject::IncHitChance( SI16 toInc )
+{
+	SetHitChance( hitChance + toInc );
+}
+
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CBaseObject::IncDefenseChance()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Increments the object's Hit Chance value
+//o------------------------------------------------------------------------------------------------o
+void CBaseObject::IncDefenseChance( SI16 toInc )
+{
+	SetDefenseChance( defenseChance + toInc );
+}
+
 //o------------------------------------------------------------------------------------------------o
 //|	Function	-	CBaseObject::DumpFooter()
 //o------------------------------------------------------------------------------------------------o
@@ -2022,6 +2276,11 @@ bool CBaseObject::HandleLine( std::string &UTag, std::string &data )
 			{
 				st2	= oldstrutil::value<SI16>( data );
 			}
+			else if( UTag == "SWINGSPEEDINC" )
+			{
+				SetSwingSpeedIncrease( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )));
+				rValue = true;
+			}
 			else if( UTag == "SCPTRIG" )
 			{
 				//scriptTrig	= oldstrutil::value<UI16>(data);
@@ -2544,7 +2803,7 @@ void CBaseObject::CopyData( CBaseObject *target )
 	target->SetIntelligence2( GetIntelligence2() );
 	target->SetPoisoned( GetPoisoned() );
 	target->SetWeight( GetWeight() );
-
+	target->SetSwingSpeedIncrease( GetSwingSpeedIncrease() );
 	target->SetKarma( karma );
 	target->SetFame( fame );
 	target->SetKills( kills );
diff --git a/source/cBaseObject.h b/source/cBaseObject.h
index 638e826f7..527f6c3b7 100644
--- a/source/cBaseObject.h
+++ b/source/cBaseObject.h
@@ -69,16 +69,25 @@ class CBaseObject
 	SI16				dexterity;
 	SI16				intelligence;
 	SI16				hitpoints;
+	SI16				hitChance;
+	SI16				defenseChance;
 	VisibleTypes		visible;
 	SI16				hiDamage;
 	SI16				loDamage;
 	SI32				weight;
 	SI16				mana;
 	SI16				stamina;
+	SI16				swingSpeedIncrease;
+	SI16				healthLeech;
+	SI16				staminaLeech;
+	SI16				manaLeech;
 	UI16				scriptTrig;
 	SI16				st2;
 	SI16				dx2;
 	SI16				in2;
+	SI16				healthBonus;
+	SI16				staminaBonus;
+	SI16				manaBonus;
 	mutable SI32		FilePosition;
 	SERIAL				tempMulti;
 	std::string			name;
@@ -223,6 +232,17 @@ class CBaseObject
 	virtual void			SetHP( SI16 newValue );
 	void					IncHP( SI16 amtToChange );
 
+	virtual SI16			GetSwingSpeedIncrease( void ) const;
+	virtual void			SetSwingSpeedIncrease( SI16 newValue );
+
+	void					IncSwingSpeedIncrease( SI16 toInc = 1 );
+
+	virtual SI16			GetHitChance( void ) const;
+	virtual void			SetHitChance( SI16 newValue );
+
+	virtual SI16			GetDefenseChance( void ) const;
+	virtual void			SetDefenseChance( SI16 newValue );
+
 	void					SetDir( UI08 newDir, bool sendUpdate = true );
 	UI08					GetDir( void ) const;
 
@@ -256,6 +276,32 @@ class CBaseObject
 	void					IncDexterity( SI16 toInc = 1 );
 	void					IncIntelligence( SI16 toInc = 1 );
 
+
+	SI16					GetHealthLeech( void ) const;
+	virtual void			SetHealthLeech( SI16 nVal );
+
+	SI16					GetStaminaLeech( void ) const;
+	virtual void			SetStaminaLeech( SI16 nVal );
+
+	SI16					GetManaLeech( void ) const;
+	virtual void			SetManaLeech( SI16 nVal );
+
+	void					IncHealthLeech( SI16 toInc = 1 );
+	void					IncStaminaLeech( SI16 toInc = 1 );
+	void					IncManaLeech( SI16 toInc = 1 );
+
+	void					IncHitChance( SI16 toInc = 1 );
+	void					IncDefenseChance( SI16 toInc = 1 );
+
+	SI16					GetHealthBonus( void ) const;
+	virtual void			SetHealthBonus( SI16 nVal );
+
+	SI16					GetStaminaBonus( void ) const;
+	virtual void			SetStaminaBonus( SI16 nVal );
+
+	SI16					GetManaBonus( void ) const;
+	virtual void			SetManaBonus( SI16 nVal );
+
 	virtual void			PostLoadProcessing( void );
 	virtual bool			LoadRemnants( void ) = 0;
 
diff --git a/source/cChar.cpp b/source/cChar.cpp
index 7aa03f6fa..319737117 100644
--- a/source/cChar.cpp
+++ b/source/cChar.cpp
@@ -2411,6 +2411,8 @@ void CChar::CopyData( CChar *target )
 	target->SetNextAct( nextAct );
 	target->SetSquelched( GetSquelched() );
 	target->SetMeditating( IsMeditating() );
+	target->SetHitChance( GetHitChance() );
+	target->SetDefenseChance( GetDefenseChance() );
 	target->SetStealth( stealth );
 	target->SetRunning( running );
 	target->SetRace( GetRace() );
@@ -2920,6 +2922,19 @@ bool CChar::WearItem( CItem *toWear )
 			IncDexterity2( itemLayers[tLayer]->GetDexterity2() );
 			IncIntelligence2( itemLayers[tLayer]->GetIntelligence2() );
 
+			IncSwingSpeedIncrease( itemLayers[tLayer]->GetSwingSpeedIncrease() );
+
+			IncHealthLeech( itemLayers[tLayer]->GetHealthLeech() );
+			IncStaminaLeech( itemLayers[tLayer]->GetStaminaLeech() );
+			IncManaLeech( itemLayers[tLayer]->GetManaLeech() );
+
+      IncHitChance( itemLayers[tLayer]->GetHitChance() );
+			IncDefenseChance( itemLayers[tLayer]->GetDefenseChance() );
+
+			IncHealthBonus( itemLayers[tLayer]->GetHealthBonus() );
+			IncStaminaBonus( itemLayers[tLayer]->GetStaminaBonus() );
+			IncManaBonus( itemLayers[tLayer]->GetManaBonus() );
+
 			if( toWear->IsPostLoaded() )
 			{
 				if( itemLayers[tLayer]->GetPoisoned() )
@@ -2979,6 +2994,20 @@ bool CChar::TakeOffItem( ItemLayers Layer )
 		IncStrength2( -itemLayers[Layer]->GetStrength2() );
 		IncDexterity2( -itemLayers[Layer]->GetDexterity2() );
 		IncIntelligence2( -itemLayers[Layer]->GetIntelligence2() );
+
+		IncSwingSpeedIncrease( -itemLayers[Layer]->GetSwingSpeedIncrease() );
+
+    IncHealthLeech( -itemLayers[Layer]->GetHealthLeech() );
+		IncStaminaLeech( -itemLayers[Layer]->GetStaminaLeech() );
+		IncManaLeech( -itemLayers[Layer]->GetManaLeech() );
+
+		IncHitChance( -itemLayers[Layer]->GetHitChance() );
+		IncDefenseChance( -itemLayers[Layer]->GetDefenseChance() );
+
+		IncHealthBonus( -itemLayers[Layer]->GetHealthBonus() );
+		IncStaminaBonus( -itemLayers[Layer]->GetStaminaBonus() );
+		IncManaBonus( -itemLayers[Layer]->GetManaBonus() );
+
 		if( itemLayers[Layer]->GetPoisoned() )
 		{
 			if( itemLayers[Layer]->GetPoisoned() > GetPoisoned() )
@@ -3134,6 +3163,8 @@ bool CChar::DumpBody( std::ostream &outStream ) const
 	//-------------------------------------------------------------------------------------------
 	outStream << "CanRun=" + std::to_string((( CanRun() && IsNpc() ) ? 1 : 0 )) + newLine;
 	outStream << "CanAttack=" + std::to_string(( GetCanAttack() ? 1 : 0 )) + newLine;
+	outStream << "HitChance=" + std::to_string( GetHitChance() ) + newLine;
+	outStream << "DefChance=" + std::to_string( GetDefenseChance() ) + newLine;
 	outStream << "AllMove=" + std::to_string(( AllMove() ? 1 : 0 )) + newLine;
 	outStream << "IsNpc=" + std::to_string(( IsNpc() ? 1 : 0 )) + newLine;
 	outStream << "IsShop=" + std::to_string(( IsShop() ? 1 : 0 )) + newLine;
@@ -3787,7 +3818,7 @@ UI16 CChar::GetMaxHP( void )
 		oldRace			= GetRace();
 
 	}
-	return maxHP;
+	return maxHP + GetHealthBonus();
 }
 void CChar::SetMaxHP( UI16 newmaxhp, UI16 newoldstr, RACEID newoldrace )
 {
@@ -3830,7 +3861,7 @@ void CChar::SetFixedMaxHP( SI16 newmaxhp )
 SI16 CChar::GetMaxMana( void )
 {
 	if(( maxMana_oldint != GetIntelligence() || oldRace != GetRace() ) && !GetMaxManaFixed() )
-		//if int/race changed since last calculation, recalculate maxHp
+		//if int/race changed since last calculation, recalculate maxMana
 	{
 		CRace *pRace = Races->Race( GetRace() );
 
@@ -3847,7 +3878,7 @@ SI16 CChar::GetMaxMana( void )
 		oldRace			= GetRace();
 
 	}
-	return maxMana;
+	return maxMana + GetManaBonus();
 }
 void CChar::SetMaxMana( SI16 newmaxmana, UI16 newoldint, RACEID newoldrace )
 {
@@ -3889,7 +3920,7 @@ void CChar::SetFixedMaxMana( SI16 newmaxmana )
 //o------------------------------------------------------------------------------------------------o
 SI16 CChar::GetMaxStam( void )
 {
-	// If dex/race changed since last calculation, recalculate maxHp
+	// If dex/race changed since last calculation, recalculate maxStam
 	if(( maxStam_olddex != GetDexterity() || oldRace != GetRace() ) && !GetMaxStamFixed() )
 	{
 		CRace *pRace = Races->Race( GetRace() );
@@ -3907,7 +3938,7 @@ SI16 CChar::GetMaxStam( void )
 		oldRace			= GetRace();
 
 	}
-	return maxStam;
+	return maxStam + GetStaminaBonus();
 }
 void CChar::SetMaxStam( SI16 newmaxstam, UI16 newolddex, RACEID newoldrace )
 {
@@ -4372,6 +4403,11 @@ bool CChar::HandleLine( std::string &UTag, std::string &data )
 					SetDead(( static_cast<UI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )) == 1 ));
 					rValue = true;
 				}
+				else if( UTag == "DEFCHANCE" )
+				{
+					SetDefenseChance( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )));
+					rValue = true;
+				}
 				break;
 			case 'E':
 				if( UTag == "EMOTION" )
@@ -4460,7 +4496,12 @@ bool CChar::HandleLine( std::string &UTag, std::string &data )
 				}
 				break;
 			case 'H':
-				if( UTag == "HUNGER" )
+				if( UTag == "HITCHANCE" )
+				{
+					SetHitChance( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )));
+					rValue = true;
+				}
+				else if( UTag == "HUNGER" )
 				{
 					SetHunger( static_cast<SI16>( std::stoi( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )));
 					rValue = true;
@@ -5593,6 +5634,74 @@ void CChar::SetIntelligence2( SI16 nVal )
 	UpdateRegion();
 }
 
+//o------------------------------------------------------------------------------------------------o
+//| Function	-	CChar::SetHealthBonus()
+//o------------------------------------------------------------------------------------------------o
+//| Purpose		-	Sets bonus Hits stat for character
+//o------------------------------------------------------------------------------------------------o
+void CChar::SetHealthBonus( SI16 nVal )
+{
+	CBaseObject::SetHealthBonus( nVal );
+	Dirty( UT_HITPOINTS );
+	UpdateRegion();
+}
+
+//o------------------------------------------------------------------------------------------------o
+//| Function	-	CChar::SetStaminaBonus()
+//o------------------------------------------------------------------------------------------------o
+//| Purpose		-	Sets bonus Stam stat for character
+//o------------------------------------------------------------------------------------------------o
+void CChar::SetStaminaBonus( SI16 nVal )
+{
+	CBaseObject::SetStaminaBonus( nVal );
+	Dirty( UT_STAMINA );
+	UpdateRegion();
+}
+
+//o------------------------------------------------------------------------------------------------o
+//| Function	-	CChar::SetManaBonus()
+//o------------------------------------------------------------------------------------------------o
+//| Purpose		-	Sets bonus Mana stat for character
+//o------------------------------------------------------------------------------------------------o
+void CChar::SetManaBonus( SI16 nVal )
+{
+	CBaseObject::SetManaBonus( nVal );
+	Dirty( UT_MANA );
+	UpdateRegion();
+}
+
+//o------------------------------------------------------------------------------------------------o
+//| Function	-	CChar::IncHealthBonus()
+//o------------------------------------------------------------------------------------------------o
+//| Purpose		-	Increments GetHealthBonus (modifications) by toAdd
+//o------------------------------------------------------------------------------------------------o
+void CChar::IncHealthBonus( SI16 toAdd )
+{
+	SetHealthBonus( static_cast<SI16>( GetHealthBonus() + toAdd ));
+}
+
+//o------------------------------------------------------------------------------------------------o
+//| Function	-	CChar::IncStaminaBonus()
+//| Date		-	26 May 2024
+//o------------------------------------------------------------------------------------------------o
+//| Purpose		-	Increments GetBonusStam (modifications) by toAdd
+//o------------------------------------------------------------------------------------------------o
+void CChar::IncStaminaBonus( SI16 toAdd )
+{
+	SetStaminaBonus( static_cast<SI16>( GetStaminaBonus() + toAdd ));
+}
+
+//o------------------------------------------------------------------------------------------------o
+//| Function	-	CChar::IncManaBonus()
+//| Date		-	26 May 2024
+//o------------------------------------------------------------------------------------------------o
+//| Purpose		-	Increments GetBonusMana (modifications) by toAdd
+//o------------------------------------------------------------------------------------------------o
+void CChar::IncManaBonus( SI16 toAdd )
+{
+	SetManaBonus( static_cast<SI16>( GetManaBonus() + toAdd ));
+}
+
 //o------------------------------------------------------------------------------------------------o
 //| Function	-	CChar::IncStamina()
 //o------------------------------------------------------------------------------------------------o
diff --git a/source/cChar.h b/source/cChar.h
index ed4cc90ba..ae387a58c 100644
--- a/source/cChar.h
+++ b/source/cChar.h
@@ -628,6 +628,15 @@ class CChar : public CBaseObject
 	virtual void	SetStrength2( SI16 newValue ) override;
 	virtual void	SetDexterity2( SI16 newValue ) override;
 	virtual void	SetIntelligence2( SI16 newValue ) override;
+
+	virtual void	SetHealthBonus( SI16 newValue ) override;
+	virtual void	SetStaminaBonus( SI16 newValue ) override;
+	virtual void	SetManaBonus( SI16 newValue ) override;
+
+	void			IncHealthBonus( SI16 toAdd = 1 );
+	void			IncStaminaBonus( SI16 toAdd = 1 );
+	void			IncManaBonus( SI16 toAdd = 1 );
+
 	void			IncStamina( SI16 toInc );
 	void			IncMana( SI16 toInc );
 	void			SetMaxLoyalty( UI16 newMaxLoyalty );
diff --git a/source/cItem.cpp b/source/cItem.cpp
index 7f12f11d2..b668ef29e 100644
--- a/source/cItem.cpp
+++ b/source/cItem.cpp
@@ -1672,13 +1672,20 @@ auto CItem::CopyData( CItem *target ) -> void
 	target->SetRndValueRate( GetRndValueRate() );
 	target->SetSpawn( GetSpawn() );
 	target->SetSpeed( GetSpeed() );
+	target->SetHitChance( GetHitChance() );
+	target->SetDefenseChance( GetDefenseChance() );
+
 	target->SetArtifactRarity( GetArtifactRarity() );
+
 	target->SetSpell( 0, GetSpell( 0 ));
 	target->SetSpell( 1, GetSpell( 1 ));
 	target->SetSpell( 2, GetSpell( 2 ));
 	target->SetStamina( GetStamina() );
 	target->SetStrength( GetStrength() );
 	target->SetStrength2( GetStrength2() );
+	target->SetHealthLeech( GetHealthLeech() );
+	target->SetStaminaLeech( GetStaminaLeech() );
+	target->SetManaLeech( GetManaLeech() );
 	target->SetTitle( GetTitle() );
 	target->SetType( GetType() );
 	target->SetBuyValue( GetBuyValue() );
@@ -1689,6 +1696,9 @@ auto CItem::CopyData( CItem *target ) -> void
 	target->SetWeightMax( GetWeightMax() );
 	target->SetBaseWeight( GetBaseWeight() );
 	target->SetMaxItems( GetMaxItems() );
+	target->SetHealthBonus( GetHealthBonus() );
+	target->SetStaminaBonus( GetStaminaBonus() );
+	target->SetManaBonus( GetManaBonus() );
 	//target->SetWipeable( IsWipeable() );
 	target->SetPriv( GetPriv() );
 	target->SetBaseRange( GetBaseRange() );
@@ -1772,11 +1782,15 @@ bool CItem::DumpBody( std::ostream &outStream ) const
 	outStream << "BaseWeight=" + std::to_string( GetBaseWeight() ) + newLine;
 	outStream << "MaxItems=" + std::to_string( GetMaxItems() ) + newLine;
 	outStream << "MaxHP=" + std::to_string( GetMaxHP() ) + newLine;
+	outStream << "HitChance=" + std::to_string( GetHitChance() ) + newLine;
+	outStream << "DefenseChance=" + std::to_string( GetDefenseChance() ) + newLine;
 	outStream << "Speed=" + std::to_string( GetSpeed() ) + newLine;
+	outStream << "BonusStats=" + std::to_string( GetHealthBonus() ) + "," + std::to_string( GetStaminaBonus() ) + "," + std::to_string( GetManaBonus() ) + newLine;
 	outStream << "ArtifactRarity=" + std::to_string( GetArtifactRarity() ) + newLine;
 	outStream << "Movable=" + std::to_string( GetMovable() ) + newLine;
 	outStream << "Priv=" + std::to_string( GetPriv() ) + newLine;
 	outStream << "LowerStatReq=" + std::to_string( GetLowerStatReq() ) + newLine;
+	outStream << "LeechStats=" + std::to_string( GetHealthLeech() ) + "," + std::to_string( GetStaminaLeech() ) + "," + std::to_string( GetManaLeech() ) + newLine;
 	outStream << "Value=" + std::to_string( GetBuyValue() ) + "," + std::to_string( GetSellValue() ) + "," + std::to_string( GetVendorPrice() ) + newLine;
 	outStream << "Restock=" + std::to_string( GetRestock() ) + newLine;
 	outStream << "AC=" + std::to_string( GetArmourClass() ) + newLine;
@@ -1863,6 +1877,13 @@ bool CItem::HandleLine( std::string &UTag, std::string &data )
 					bools = static_cast<UI08>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ));
 					rValue = true;
 				}
+				else if( UTag == "BONUSSTATS" )
+				{
+				    SetHealthBonus( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[0], "//" )), nullptr, 0 )));
+				    SetStaminaBonus( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[1], "//" )), nullptr, 0 )));
+				    SetManaBonus( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[2], "//" )), nullptr, 0 )));
+				    rValue = true;
+				}
 				break;
 			case 'C':
 				if( UTag == "CONT" )
@@ -1902,6 +1923,11 @@ bool CItem::HandleLine( std::string &UTag, std::string &data )
 					SetDye( static_cast<UI08>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )) == 1 );
 					rValue = true;
 				}
+				else if( UTag == "DEFENSECHANCE" )
+				{
+					SetDefenseChance( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )));
+					rValue = true;
+				}
 				break;
 			case 'E':
 				if( UTag == "ENTRYMADEFROM" )
@@ -1948,6 +1974,11 @@ bool CItem::HandleLine( std::string &UTag, std::string &data )
 					SetWeatherDamage( HEAT, static_cast<UI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )) == 1 );
 					rValue = true;
 				}
+				else if( UTag == "HITCHANCE" )
+				{
+					SetHitChance( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )));
+					rValue = true;
+				}
 				break;
 			case 'L':
 				if( UTag == "LAYER" )
@@ -1970,6 +2001,13 @@ bool CItem::HandleLine( std::string &UTag, std::string &data )
 					SetLowerStatReq( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )));
 					rValue = true;
 				}
+				else if( UTag == "LEECHSTATS" )
+				{
+					SetHealthLeech( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[0], "//" )), nullptr, 0 )));
+					SetStaminaLeech( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[1], "//" )), nullptr, 0 )));
+					SetManaLeech( static_cast<SI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[2], "//" )), nullptr, 0 )));
+					rValue = true;
+				}
 				break;
 			case 'M':
 				if( UTag == "MAXITEMS" )
diff --git a/source/cServerData.cpp b/source/cServerData.cpp
index 3f57745a8..baebacaf7 100644
--- a/source/cServerData.cpp
+++ b/source/cServerData.cpp
@@ -369,7 +369,8 @@ const std::map<std::string, SI32> CServerData::uox3IniCaseValue
 	{"SECRETSHARDKEY"s, 346},
 	{"MOONGATEFACETS"s, 347},
 	{"AUTOUNEQUIPPEDCASTING"s, 348},
-	{"LOOTDECAYSWITHNPCCORPSE"s, 349}
+	{"LOOTDECAYSWITHNPCCORPSE"s, 349},
+	{"SWINGSPEEDINCREASECAP"s, 353}
 };
 constexpr auto MAX_TRACKINGTARGETS = 128;
 constexpr auto SKILLTOTALCAP = 7000;
@@ -723,6 +724,7 @@ auto CServerData::ResetDefaults() -> void
 	PetCombatTraining( true );
 	HirelingCombatTraining( true );
 	NpcCombatTraining( false );
+	SwingSpeedIncreaseCap( 60 );
 	WeaponDamageBonusType( 2 );
 
 	CheckPetControlDifficulty( true );
@@ -5196,7 +5198,7 @@ auto CServerData::SaveIni( const std::string &filename ) -> bool
 		ofsOutput << "SHOWITEMRESISTSTATS=" << ( ShowItemResistStats() ? 1 : 0 ) << '\n';
 		ofsOutput << "SHOWWEAPONDAMAGETYPES=" << ( ShowWeaponDamageTypes() ? 1 : 0 ) << '\n';
 		ofsOutput << "WEAPONDAMAGEBONUSTYPE=" << static_cast<UI16>( WeaponDamageBonusType() ) << '\n';
-
+		ofsOutput << "WEAPONSWINGSPEEDINCREASECAP=" << SwingSpeedIncreaseCap() << '\n';
 		ofsOutput << "}" << '\n';
 
 		ofsOutput << '\n' << "[magic]" << '\n' << "{" << '\n';
@@ -5395,6 +5397,20 @@ auto CServerData::TrackingRedisplayTime( UI16 value ) -> void
 	trackingMsgRedisplayTimer = value;
 }
 
+//o------------------------------------------------------------------------------------------------o
+//|	Function	-	CServerData::SwingSpeedIncreaseCap()
+//o------------------------------------------------------------------------------------------------o
+//|	Purpose		-	Gets/Sets the for swing speed cap propertie
+//o------------------------------------------------------------------------------------------------o
+auto CServerData::SwingSpeedIncreaseCap() const -> SI16
+{
+	return swingSpeedIncreaseCap;
+}
+auto CServerData::SwingSpeedIncreaseCap( SI16 value ) -> void
+{
+	swingSpeedIncreaseCap = value;
+}
+
 
 //o------------------------------------------------------------------------------------------------o
 //|	Function	-	CServerData::ParseIni()
@@ -6565,6 +6581,9 @@ auto CServerData::HandleLine( const std::string& tag, const std::string& value )
 		case 349:	 // LOOTDECAYSWITHNPCCORPSE
 			NpcCorpseLootDecay( static_cast<UI16>( std::stoul( value, nullptr, 0 )) != 0 );
 			break;
+		case 353:	// SWINGSPEEDINCREASE
+			SwingSpeedIncreaseCap( std::stof( value ));
+			break;
 		default:
 			rValue = false;
 			break;
diff --git a/source/cServerData.h b/source/cServerData.h
index d770645c8..3abf534e0 100644
--- a/source/cServerData.h
+++ b/source/cServerData.h
@@ -400,6 +400,7 @@ class CServerData
 	SI16		combatNpcBaseFleeAt;			//	% of HP where an NPC will flee, if it's not defined for them
 	SI16		combatNpcBaseReattackAt;		//	% of HP where an NPC will resume attacking
 	SI16		combatAttackStamina;			//	Amount of stamina lost when hitting an opponent
+	SI16		swingSpeedIncreaseCap;			//	The Cap for swing speed property
 
 	// Start & Location Settings
 	std::vector<__STARTLOCATIONDATA__>	startlocations;
@@ -953,6 +954,9 @@ class CServerData
 	auto		BODsFromCraftedItemsOnly( bool value ) -> void;
 	auto		BODsFromCraftedItemsOnly() const -> bool;
 
+	auto		SwingSpeedIncreaseCap( SI16 value ) -> void;
+	SI16		SwingSpeedIncreaseCap() const;
+
 	auto		MaxControlSlots( UI08 value ) -> void;
 	UI08		MaxControlSlots() const;
 
diff --git a/source/combat.cpp b/source/combat.cpp
index 8817d7b3d..6712aa0a8 100644
--- a/source/combat.cpp
+++ b/source/combat.cpp
@@ -801,6 +801,10 @@ UI08 CHandleCombat::GetWeaponType( CItem *i )
 		case 0x48B3: //gargish axe - SA
 			return TWOHND_AXES;
 		// Default Maces
+		case 0x0DF2: // Wand
+		case 0x0DF3: // Wand
+		case 0x0DF4: // Wand
+		case 0x0DF5: // Wand
 		case 0x13E3: //smith's hammer
 		case 0x13E4: //smith's hammer
 		case 0x13B3: //club
@@ -2645,7 +2649,7 @@ SI16 CHandleCombat::ApplyDefenseModifiers( WeatherType damageType, CChar *mChar,
 
 	if( getDef > 0 )
 	{
-		damage -= static_cast<R32>(( static_cast<R32>( getDef ) * static_cast<R32>( attSkill )) / 750 );
+		damage -= static_cast<R32>( getDef );
 	}
 
 	return static_cast<SI16>( std::round( damage ));
@@ -2877,18 +2881,24 @@ bool CHandleCombat::HandleCombat( CSocket *mSock, CChar& mChar, CChar *ourTarg )
 				R32 attHitChanceBonus = 0;
 				R32 defDefenseChanceBonus = 0;
 				R32 maxAttHitChanceBonus = 45;
+
 				if( cwmWorldState->ServerData()->ExpansionCombatHitChance() >= ER_SA && mChar.GetBodyType() == BT_GARGOYLE )
 				{
 					// If attacker is a Gargoyle player, and ExpansionCombatHitChance is ER_SA or higher, use 50 as hitchance bonus cap instead of 45
 					maxAttHitChanceBonus = 50;
 				}
 				
-				// Fetch bonuses to hitChance/defenseChance from AoS item properties, when implemented
-				//attHitChanceBonus = GetAttackerHitChanceBonus();
-				//defDefenseChanceBonus = GetDefenderDefenseChanceBonus();
+				// Fetch bonuses to hitChance/defenseChance from AoS item properties or characters
+				attHitChanceBonus = mChar.GetHitChance();
+				defDefenseChanceBonus = mChar.GetDefenseChance();
+
+				// Clamp to ensure valid bonus ranges (e.g., no multiplier below 1)
+				R32 effectiveAttHitChanceBonus = std::max(-99.0f, std::min( attHitChanceBonus, maxAttHitChanceBonus )); // Cap at -99 and maxAttHitChanceBonus
+				R32 effectiveDefDefenseChanceBonus = std::max(-99.0f, std::min( defDefenseChanceBonus, 45.0f )); // Cap at -99 and 45
 
-				R32 attackerHitChance = ( static_cast<R32>( attackSkill / 10 ) + 20 ) * ( 100 + std::min( attHitChanceBonus, static_cast<R32>( maxAttHitChanceBonus )));
-				R32 defenderDefenseChance = ( static_cast<R32>( defendSkill / 10 ) + 20 ) * ( 100 + std::min( defDefenseChanceBonus, static_cast<R32>( 45 )));
+				// Calculate the attacker's hit chance and defender's defense chance
+				R32 attackerHitChance = ( static_cast<R32>( attackSkill / 10 ) + 20 ) * ( 100 + effectiveAttHitChanceBonus );
+				R32 defenderDefenseChance = ( static_cast<R32>( defendSkill / 10 ) + 20 ) * ( 100 + effectiveDefDefenseChanceBonus );
 				hitChance = ( attackerHitChance / ( defenderDefenseChance * 2 )) * 100;
 
 				// Always leave at least 2% chance to hit
@@ -3430,7 +3440,8 @@ R32 CHandleCombat::GetCombatTimeout( CChar *mChar )
 	}
 
 	SI32 getOffset	= 0;
-	SI32 baseValue	= 15000;
+	SI32 baseValue = ( cwmWorldState->ServerData()->ExpansionCoreShardEra() <= ER_LBR ) ? 15000 :
+					(( cwmWorldState->ServerData()->ExpansionCoreShardEra() < ER_ML ) ? 80000 : 40000 );
 
 	CChar *ourTarg = mChar->GetTarg();
 
@@ -3455,18 +3466,49 @@ R32 CHandleCombat::GetCombatTimeout( CChar *mChar )
 		}
 	}
 
+	SI32 speedBonus = mChar->GetSwingSpeedIncrease();
+	
+	// Swing Speed Increase Cap per AOS
+	if ( speedBonus > cwmWorldState->ServerData()->SwingSpeedIncreaseCap() )
+	{
+		speedBonus = cwmWorldState->ServerData()->SwingSpeedIncreaseCap();
+	}
+
 	//Allow faster strikes on fleeing targets
 	if( ValidateObject( ourTarg ))
 	{
 		if( ourTarg->GetNpcWander() == WT_FLEE || ourTarg->GetNpcWander() == WT_SCARED )
 		{
-			baseValue = 10000;
+			baseValue = ( cwmWorldState->ServerData()->ExpansionCoreShardEra() <= ER_LBR ) ? 10000 : 
+						(( cwmWorldState->ServerData()->ExpansionCoreShardEra() < ER_ML ) ? 53333 : 26680 );
 		}
 	}
 
 	R32 globalAttackSpeed = cwmWorldState->ServerData()->GlobalAttackSpeed(); //Defaults to 1.0
 
-	getDelay = ( baseValue / ( getDelay * getOffset )) / globalAttackSpeed;
+	R32 speedFactor = 1 + speedBonus / 10.0f;
+
+	// Prevent zero or negative multipliers
+	if( speedFactor < 0.1f )
+		speedFactor = 0.1f;
+
+
+	if( cwmWorldState->ServerData()->ExpansionCoreShardEra() <= ER_LBR )
+	{
+		// Weapon swing delay in LBR and earlier
+		getDelay = baseValue / ( getDelay * getOffset * speedFactor ) / globalAttackSpeed;
+	}
+	else if( cwmWorldState->ServerData()->ExpansionCoreShardEra() < ER_ML )
+	{
+		// Weapon swing delay in SE or earlier
+		getDelay = ( baseValue / ( getDelay * getOffset * speedFactor ) / 4 - 0.5 ) / globalAttackSpeed;
+	}
+	else
+	{
+		// Weapon swing delay in ML or later
+		getDelay = ( baseValue / ( getDelay * getOffset * speedFactor ) * 0.5 ) / globalAttackSpeed;
+	}
+
 	return getDelay;
 }
 
diff --git a/source/enums.h b/source/enums.h
index 1383bbd10..16db01f95 100644
--- a/source/enums.h
+++ b/source/enums.h
@@ -373,8 +373,8 @@ enum Skills
     BUSHIDO,
     NINJITSU,
     SPELLWEAVING,
-    IMBUING,
     MYSTICISM,
+    IMBUING,
     THROWING,
 
     ALLSKILLS, // #skills+1
diff --git a/source/items.cpp b/source/items.cpp
index 33cc4335e..5951c4a36 100644
--- a/source/items.cpp
+++ b/source/items.cpp
@@ -139,7 +139,13 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect
 				}
 				break;
 			case DFNTAG_AC:				applyTo->SetArmourClass( static_cast<UI08>( ndata ));	break;
+			case DFNTAG_HEALTHLEECH:	applyTo->SetHealthLeech( static_cast<SI16>( ndata ));		break;
+			case DFNTAG_STAMINALEECH:	applyTo->SetStaminaLeech( static_cast<SI16>( ndata ));		break;
+			case DFNTAG_MANALEECH:		applyTo->SetManaLeech( static_cast<SI16>( ndata ));		break;
 			case DFNTAG_BASERANGE:		applyTo->SetBaseRange( static_cast<UI08>( ndata ));		break;
+			case DFNTAG_HEALTHBONUS:		applyTo->SetHealthBonus( static_cast<SI16>( ndata ));		break;
+			case DFNTAG_STAMINABONUS:		applyTo->SetStaminaBonus( static_cast<SI16>( ndata ));		break;
+			case DFNTAG_MANABONUS:		applyTo->SetManaBonus( static_cast<SI16>( ndata ));		break;
 			case DFNTAG_CREATOR:		applyTo->SetCreator( ndata );							break;
 			case DFNTAG_COLOUR:			applyTo->SetColour( static_cast<UI16>( ndata ));		break;
 			case DFNTAG_COLOURLIST:		applyTo->SetColour( AddRandomColor( cdata ));			break;
@@ -230,6 +236,7 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect
 			case DFNTAG_DISPELLABLE:	applyTo->SetDispellable( true );			break;
 			case DFNTAG_DISABLED:		applyTo->SetDisabled( ndata != 0 );			break;
 			case DFNTAG_DOORFLAG:		break;
+			case DFNTAG_DEFENSECHANCE:	applyTo->SetDefenseChance( static_cast<SI16>( ndata ));		break;
 			case DFNTAG_GOOD:			applyTo->SetGood( static_cast<SI16>( ndata ));			break;
 			case DFNTAG_GLOW:			applyTo->SetGlow( ndata );								break;
 			case DFNTAG_GLOWBC:			applyTo->SetGlowColour( static_cast<UI16>( ndata ));	break;
@@ -339,6 +346,7 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect
 				}
 				break;
 			case DFNTAG_HIDAMAGE:		applyTo->SetHiDamage( static_cast<SI16>( ndata ));		break;
+			case DFNTAG_HITCHANCE:	applyTo->SetHitChance( static_cast<SI16>( ndata ));		break;
 			case DFNTAG_HEAT:			applyTo->SetWeatherDamage( HEAT, ndata != 0 );			break;
 			case DFNTAG_ID:				// applyTo->SetId( static_cast<UI16>( ndata ));				break;
 				if( ssecs.size() == 1 )
@@ -550,6 +558,7 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect
 			case DFNTAG_RAIN:			applyTo->SetWeatherDamage( RAIN, ndata != 0 );			break;
 			case DFNTAG_SECTIONID:		applyTo->SetSectionId( cdata );							break;
 			case DFNTAG_SK_MADE:		applyTo->SetMadeWith( static_cast<SI08>( ndata ));		break;
+			case DFNTAG_SWINGSPEEDINCREASE:	applyTo->SetSwingSpeedIncrease( static_cast<SI16>( ndata ));		break;
 			case DFNTAG_SPD:			applyTo->SetSpeed( static_cast<UI08>( ndata ));			break;
 			case DFNTAG_STRENGTH:		applyTo->SetStrength( static_cast<SI16>( ndata ));		break;
 			case DFNTAG_STRADD:			applyTo->SetStrength2( static_cast<SI16>( ndata ));		break;
diff --git a/source/npcs.cpp b/source/npcs.cpp
index 36005b420..41536fea6 100644
--- a/source/npcs.cpp
+++ b/source/npcs.cpp
@@ -1541,6 +1541,8 @@ auto CCharStuff::ApplyNpcSection( CChar *applyTo, CScriptSection *NpcCreation, s
 			case DFNTAG_NAMELIST:			SetRandomName( applyTo, cdata );		break;
 			case DFNTAG_NECROMANCY:			skillToSet = NECROMANCY;				break;
 			case DFNTAG_NINJITSU:			skillToSet = NINJITSU;					break;
+			case DFNTAG_HITCHANCE:			applyTo->SetHitChance( static_cast<SI16>( ndata ));		break;
+			case DFNTAG_DEFENSECHANCE:		applyTo->SetDefenseChance( static_cast<SI16>( ndata ));		break;
 			case DFNTAG_NPCWANDER:
 				if( !isGate )
 				{
@@ -1583,6 +1585,7 @@ auto CCharStuff::ApplyNpcSection( CChar *applyTo, CScriptSection *NpcCreation, s
 			case DFNTAG_PEACEMAKING:		skillToSet = PEACEMAKING;				break;
 			case DFNTAG_PROVOCATION:		skillToSet = PROVOCATION;				break;
 			case DFNTAG_POISONING:			skillToSet = POISONING;					break;
+			case DFNTAG_SWINGSPEEDINCREASE:	applyTo->SetSwingSpeedIncrease( static_cast<SI16>( ndata ));		break;
 			case DFNTAG_RESISTFIRE:
 				if( ndata >= 0 )
 				{
diff --git a/source/ssection.cpp b/source/ssection.cpp
index ecaa450a1..6d89e606f 100644
--- a/source/ssection.cpp
+++ b/source/ssection.cpp
@@ -67,6 +67,7 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] =
 	DFN_NUMERIC,		//	DFNTAG_DOORFLAG,
 	DFN_NUMERIC,		//	DFNTAG_DYE,
 	DFN_NUMERIC,		//	DFNTAG_DYEBEARD,
+	DFN_NUMERIC,		//	DFNTAG_DEFENSECHANCE,
 	DFN_NUMERIC,		//	DFNTAG_DYEHAIR,
 	DFN_STRING,			//	DFNTAG_ELEMENTRESIST,
 	DFN_STRING,			//	DFNTAG_ERBONUS,
@@ -112,10 +113,12 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] =
 	DFN_NUMERIC,		//	DFNTAG_HEAT,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_HERDING,
 	DFN_NUMERIC,		//	DFNTAG_HIDAMAGE,
+	DFN_NUMERIC,		//	DFNTAG_HITCHANCE,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_HIDING,
 	DFN_NODATA,			//	DFNTAG_HIRELING,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_HP,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_HPMAX,
+	DFN_NUMERIC,		//  DFNTAG_HEALTHLEECH,
 	DFN_UPPERSTRING,	//	DFNTAG_ID,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_IMBUING,
 	DFN_NUMERIC,		//	DFNTAG_INTADD,
@@ -142,6 +145,7 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] =
 	DFN_DOUBLENUMERIC,	//	DFNTAG_MAGICRESISTANCE,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_MANA,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_MANAMAX,
+	DFN_NUMERIC,		//  DFNTAG_MANALEECH,
 	DFN_NUMERIC,		//	DFNTAG_MAXHP,
 	DFN_NUMERIC,		//	DFNTAG_MAXITEMS,
 	DFN_NUMERIC,		//	DFNTAG_MAXLOYALTY,
@@ -217,6 +221,9 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] =
 	DFN_STRING,			//	DFNTAG_SPAWNOBJ,
 	DFN_STRING,			//	DFNTAG_SPAWNOBJLIST,
 	DFN_NUMERIC,		//	DFNTAG_SPD,
+	DFN_NUMERIC,		//  DFNTAG_HEALTHBONUS,
+	DFN_NUMERIC,		//  DFNTAG_STAMINABONUS,
+	DFN_NUMERIC,		//  DFNTAG_MANABONUS,
 	DFN_STRING,			//	DFNTAG_SPELLS,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_SPELLWEAVING,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_SPIRITSPEAK,
@@ -224,12 +231,14 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] =
 	DFN_NUMERIC,		//	DFNTAG_SPLITCHANCE,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_STAMINA,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_STAMINAMAX,
+	DFN_NUMERIC,		//  DFNTAG_STAMINALEECH,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_STRENGTH,
 	DFN_NUMERIC,		//	DFNTAG_STRADD,
 	DFN_NUMERIC,		//	DFNTAG_STEALABLE,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_STEALING,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_STEALTH,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_SWORDSMANSHIP,
+	DFN_NUMERIC,		//  DFNTAG_SWINGSPEEDINCREASE,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_TACTICS,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_TAILORING,
 	DFN_DOUBLENUMERIC,	//	DFNTAG_TAMING,
@@ -286,6 +295,9 @@ const std::map<std::string, DFNTAGS> strToDFNTag
 	{"BLACKSMITHING"s,		DFNTAG_BLACKSMITHING},
 	{"BOWCRAFT"s,			DFNTAG_BOWCRAFT},
 	{"BUSHIDO"s,			DFNTAG_BUSHIDO},
+	{"HEALTHBONUS"s,		DFNTAG_HEALTHBONUS},
+	{"STAMINABONUS"s,		DFNTAG_STAMINABONUS},
+	{"MANABONUS"s,			DFNTAG_MANABONUS},
 	{"CAMPING"s,			DFNTAG_CAMPING},
 	{"CARPENTRY"s,			DFNTAG_CARPENTRY},
 	{"CARTOGRAPHY"s,		DFNTAG_CARTOGRAPHY},
@@ -324,6 +336,7 @@ const std::map<std::string, DFNTAGS> strToDFNTag
 	{"DYEABLE"s,			DFNTAG_DYE},
 	{"DYEHAIR"s,			DFNTAG_DYEHAIR},
 	{"DYEBEARD"s,			DFNTAG_DYEBEARD},
+	{"DEFENSECHANCE"s,		DFNTAG_DEFENSECHANCE},
 	{"ELEMENTRESIST"s,		DFNTAG_ELEMENTRESIST},
 	{"ERBONUS"s,			DFNTAG_ERBONUS},	
 	{"EMOTECOLOR"s,			DFNTAG_EMOTECOLOUR},
@@ -369,10 +382,12 @@ const std::map<std::string, DFNTAGS> strToDFNTag
 	{"HEAT"s,				DFNTAG_HEAT},
 	{"HERDING"s,			DFNTAG_HERDING},
 	{"HIDAMAGE"s,			DFNTAG_HIDAMAGE},
+	{"HITCHANCE"s,			DFNTAG_HITCHANCE},
 	{"HIDING"s,				DFNTAG_HIDING},
 	{"HIRELING"s,			DFNTAG_HIRELING},
 	{"HP"s,					DFNTAG_HP},
 	{"HPMAX"s,				DFNTAG_HPMAX},
+	{"HEALTHLEECH"s,		DFNTAG_HEALTHLEECH},
 	{"ID"s,					DFNTAG_ID},
 	{"IMBUING"s,			DFNTAG_IMBUING},
 	{"IN"s,					DFNTAG_INTELLIGENCE},
@@ -403,6 +418,7 @@ const std::map<std::string, DFNTAGS> strToDFNTag
 	{"MAGICRESISTANCE"s,	DFNTAG_MAGICRESISTANCE},
 	{"MANA"s,				DFNTAG_MANA},
 	{"MANAMAX"s,			DFNTAG_MANAMAX},
+	{"MANALEECH"s,			DFNTAG_MANALEECH},
 	{"MAXHP"s,				DFNTAG_MAXHP},
 	{"MAXITEMS"s,			DFNTAG_MAXITEMS},
 	{"MAXLOYALTY"s,			DFNTAG_MAXLOYALTY},
@@ -479,6 +495,7 @@ const std::map<std::string, DFNTAGS> strToDFNTag
 	{"SPAWNOBJLIST"s,		DFNTAG_SPAWNOBJLIST},
 	{"SPD"s,				DFNTAG_SPD},
 	{"SPEED"s,				DFNTAG_SPD},
+	{"SWINGSPEEDINCREASE"s,	DFNTAG_SWINGSPEEDINCREASE},
 	{"SPELLS"s,				DFNTAG_SPELLS},
 	{"SPELLWEAVING"s,		DFNTAG_SPELLWEAVING},
 	{"SPIRITSPEAK"s,		DFNTAG_SPIRITSPEAK},
@@ -487,6 +504,7 @@ const std::map<std::string, DFNTAGS> strToDFNTag
 	{"ST"s,					DFNTAG_STRENGTH},
 	{"STAMINA"s,			DFNTAG_STAMINA},
 	{"STAMINAMAX"s,			DFNTAG_STAMINAMAX},
+	{"STAMINALEECH"s,		DFNTAG_STAMINALEECH},
 	{"STR"s,				DFNTAG_STRENGTH},
 	{"STRENGTH"s,			DFNTAG_STRENGTH},
 	{"ST2"s,				DFNTAG_STRADD},
diff --git a/source/ssection.h b/source/ssection.h
index 8370fca73..0c5bcfbbc 100644
--- a/source/ssection.h
+++ b/source/ssection.h
@@ -72,6 +72,7 @@ enum DFNTAGS
 	DFNTAG_DISPELLABLE,
 	DFNTAG_DISABLED,
 	DFNTAG_DOORFLAG,
+	DFNTAG_DEFENSECHANCE,
 	DFNTAG_DYE,
 	DFNTAG_DYEBEARD,
 	DFNTAG_DYEHAIR,
@@ -119,10 +120,12 @@ enum DFNTAGS
 	DFNTAG_HEAT,
 	DFNTAG_HERDING,
 	DFNTAG_HIDAMAGE,
+	DFNTAG_HITCHANCE,
 	DFNTAG_HIDING,
 	DFNTAG_HIRELING,
 	DFNTAG_HP,
 	DFNTAG_HPMAX,
+	DFNTAG_HEALTHLEECH,
 	DFNTAG_ID,
 	DFNTAG_IMBUING,
 	DFNTAG_INTADD,
@@ -149,6 +152,7 @@ enum DFNTAGS
 	DFNTAG_MAGICRESISTANCE,
 	DFNTAG_MANA,
 	DFNTAG_MANAMAX,
+	DFNTAG_MANALEECH,
 	DFNTAG_MAXHP,
 	DFNTAG_MAXITEMS,
 	DFNTAG_MAXLOYALTY,
@@ -223,7 +227,11 @@ enum DFNTAGS
 	DFNTAG_SPATTACK,
 	DFNTAG_SPAWNOBJ,
 	DFNTAG_SPAWNOBJLIST,
+	DFNTAG_SWINGSPEEDINCREASE,
 	DFNTAG_SPD,
+	DFNTAG_HEALTHBONUS,
+	DFNTAG_STAMINABONUS,
+	DFNTAG_MANABONUS,
 	DFNTAG_SPELLS,
 	DFNTAG_SPELLWEAVING,
 	DFNTAG_SPIRITSPEAK,
@@ -231,6 +239,7 @@ enum DFNTAGS
 	DFNTAG_SPLITCHANCE,
 	DFNTAG_STAMINA,
 	DFNTAG_STAMINAMAX,
+	DFNTAG_STAMINALEECH,
 	DFNTAG_STRENGTH,
 	DFNTAG_STRADD,
 	DFNTAG_STEALABLE,