Updates to Magic Item Generation

Got any custom JavaScript additions/tweaks you think other people would like to see? Post 'em here!
Post Reply
Azzerhoden
UOX3 Newbie
Posts: 16
Joined: Wed Oct 05, 2022 3:10 pm
Has thanked: 0
Been thanked: 8 times

Updates to Magic Item Generation

Post by Azzerhoden »

Attached is magic_items.js that includes some changes I made that include the following:
  • Expanded the list of wands/staves to now generate up to 25 different types across the 5 levels. The number of charges in the wand varies based on level.
  • Expanded Jewlery options. Instead of just magic rings, this script will generate magic earrings, bracelets and necklaces. Uses tier value to specify which.
  • Expanded the types of magic jewelry being generated to 23 different types of magic
  • Moved the magic weapons around in the tiers, moving longswords to teir 3, and the rest of the tier 2 items to tier 1. Moved bows, crossbows, and the expanded bows/crossbox to tier 2. The value weapons sell for is based on value in magic_items.dfn plus abilities.
  • Adjust magic armor so that it also has a vendor price based on it's abilities, similar to weapons.
  • Added magic clothing and shoes. Abilities and value similar to armor.
  • Added filtering to allow for the setting of Buy, Sell, and Restock options in magic_items.dfn for items, modified by the above
  • Finally, removed the random downgrading of items so that there is consistency in the price of weapons/armors/wands for vendors.
Weapons, Armor, and Clothing use tiers to determine the type of item being generated. Because two magic items of the same type can have 1 or more magical abilities, the first number in value is a base number that will increase for each ability that magic item has. This is not the same for Wands/Staves/Jewelry, because each only has 1 abaility.

To support the changes in magic_items.js and the selling of magic items, you can modify/add the following to the magic_items.dfn file. Note the addition of restock and value to the entries.

Code: Select all

// Random magic weapon -  Tier 1
[random_magic_weapon_1]
{
get=base_item
id=0x0f5e
morex=100
morey=0
restock=0
value=2000 50
script=3300
}

// Random magic weapon -  Tier 2
[random_magic_weapon_2]
{
get=base_item
id=0x0f5e
morex=3001
morey=0
restock=0
value=3000 50
script=3300
}

// Random magic weapon -  Tier 3
[random_magic_weapon_3]
{
get=base_item
id=0x0f5e
morex=6001
morey=0
restock=0
value=4000 50
script=3300
}

// Random magic weapon -  Tier 4
[random_magic_weapon_4]
{
get=base_item
id=0x0f5e
morex=8001
morey=0
restock=0
value=8000 50
script=3300
}

// Random magic weapon -  Tier 5
[random_magic_weapon_5]
{
get=base_item
id=0x0f5e
morex=10001
morey=0
restock=0
value=10000 50
script=3300
}
Magic Armors

Code: Select all

// Random magic armor -  Tier 1
[random_magic_armor_1]
{
get=base_item
id=0x0f5e
morex=100
morey=1
restock=0
value=2000 50
script=3300
}

// Random magic armor -  Tier 2
[random_magic_armor_2]
{
get=base_item
id=0x0f5e
morex=3001
morey=1
restock=0
value= 3000 50
script=3300
}

// Random magic armor -  Tier 3
[random_magic_armor_3]
{
get=base_item
id=0x0f5e
morex=6001
morey=1
restock=0
value=4000 50
script=3300
}

// Random magic armor -  Tier 4
[random_magic_armor_4]
{
get=base_item
id=0x0f5e
morex=8001
morey=1
restock=0
value=5000 50
script=3300
}

// Random magic armor -  Tier 5
[random_magic_armor_5]
{
get=base_item
id=0x0f5e
morex=10001
morey=1
restock=0
value=7500 50
script=3300
}
Wands and Staves

Code: Select all

// Random magic wands/staves -  Tier 1
[random_magic_wand_1]
{
get=base_item
id=0x0df2
morex=100
morey=2
restock=0
value=3500 100
script=3300
}

// Random magic wands/staves -  Tier 2
[random_magic_wand_2]
{
get=base_item
id=0x0df2
morex=3001
morey=2
restock=0
value=5000 100
script=3300
}

// Random magic wands/staves - Tier 3
[random_magic_wand_3]
{
get=base_item
id=0x0df2
morex=6001
morey=2
restock=0
value=7500 100
script=3300
}

// Random magic wands/staves - Tier 4
[random_magic_wand_4]
{
get=base_item
id=0x0df2
morex=8001
morey=2
restock=0
value=8000 100
script=3300
}

// Random magic wands/staves - Tier 5
[random_magic_wand_5]
{
get=base_item
id=0x0df2
morex=10001
morey=2
restock=0
value=10000 100
script=3300
}
For the expanded jewelry section

Code: Select all

// Random magic necklace
// Random magic ring
[random_magic_ring]
{
get=base_item
id=0x108a
morex=100
morey=3
restock=0
value=10000 100
script=3300
}

// Random magic necklace
[random_magic_necklace]
{
get=base_item
id=0x1088
morex=3001
morey=3
restock=0
value=10000 100
script=3300
}

// Random magic Earrings
[random_magic_earrings]
{
get=base_item
id=0x1087
morex=6001
morey=3
restock=0
value=10000 100
script=3300
}

// Random magic bracelet
[random_magic_bracelet]
{
get=base_item
id=0x1086
morex=8001
morey=3
restock=0
value=10000 100
script=3300
}
And for shoes and clothing

Code: Select all

// Random magic footware
[random_magic_shoes]
{
get=base_item
id=0x0f5e
morex=100
morey=4
restock=0
value=2500 100
script=3300
}

// Random magic clothing
[random_magic_clothing]
{
get=base_item
id=0x0f5e
morex=3001
morey=4
restock=0
value=2500 100
script=3300
}
Last, for .dfn changes, you must add the item to the vendors you want selling the items in the shoplists.dfn (not attached)

Code: Select all

SELLITEM=random_magic_armor_3
to sell a piece of magic armor of type 3 on that vendor.
Last edited by Azzerhoden on Fri Oct 21, 2022 3:32 pm, edited 1 time in total.
These users thanked the author Azzerhoden for the post (total 2):
Xuridragon slayer
Azzerhoden
UOX3 Newbie
Posts: 16
Joined: Wed Oct 05, 2022 3:10 pm
Has thanked: 0
Been thanked: 8 times

Post by Azzerhoden »

And now the changes to the magic_items.js file.
// Magical Items, Pre-AoS style
// v1.0
// by Xuri
// Last updated August 25thrd, 2021
//

// // Define the scriptID you've assigned to this script here:
const magicItemScriptID = 3300;
const accBonusScriptID = 3301;
const armorSpellsScriptID = 3302;
const magicWeaponSpellScriptID = 3304;

// Enable to dump generated magic item names to .txt files within the UOX3/shared folder
const outputMagicItemNamesToFile = false;

// How should we apply the damage-bonuses from Ruin/Might/Force/Power/Vanquishing to weapons?
// 0 = (Default) apply all bonus damage to weapon's max potential damage output
// 1 = split the bonus damage between min (~50%) and max (~50%) potential damage output
const dmgBonusType = 0;

// Let's define the various tiers of NPCs based on their amount of Fame
// Note: Tier 5 is not defined, but any NPCs with fame above the defined value for tier 4 belongs to tier 5
const tier1NPCFame = 3000;
const tier2NPCFame = 6000;
const tier3NPCFame = 8000;
const tier4NPCFame = 10000;

// Define the droprate for each tier of NPCs
// Works roughly like this: 1 in every X NPCs will get magic item loot
var tier1DropRate = 100;   // 45   then 22
var tier2DropRate = 50;   // 37  then 15
var tier3DropRate = 25;   // 28  then 8
var tier4DropRate = 15;   // 16  then 4
var tier5DropRate = 5;   // 2

// Adjust global drop rate across all tiers at once
// 0.5 will halve the droprate for each tier
// 1 is the default
// 2 will double the droprate for each tier
const globalDropRateMod = 1;

// Here we sort all items into tiers roughly based on their power/popularity
// Magical items from all tiers can drop from any monster, but the lower
// the fame of the monster, the more likely it will be to get a magical item
// from the lowest tiers, with the weakest magical properties. And vice versa.

// Tier 1: Smith Hammers, Crooks, Sledge Hammers, Pickaxes, Skinning Knives, Cleavers, Butcher Knives, Hatchets, Hammer Picks, Pitchforks, Clubs, Daggers
const tier1weapons = new Array( "0x13E3", "0x13E4", "0x0E81", "0x0E82", "0x13F4", "0x13F5", "0x0FB4", "0x0FB5", "0x0E85", "0x0E86", "0x0EC4", "0x0EC5", "0x0EC2", "0x0EC3", "0x13F6", "0x13F7","0x0F43", "0x0F44", "0x143C", "0x143D", "0x0E87", "0x0E88", "0x13B3", "0x13B4", "0x0F51", "0x0F52" );
// Tier 2: Heavy Crossbows, Composite Bows, Repeating Crossbows, Elvan Bows, Silverwood Bows, Yumi, Crossbows, Bows,
const tier2weapons = new Array( "0x13FC", "0x13FD", "0x26c2", "0x26cc", "0x26c3", "0x26cd", "0x2D1E", "0x2d2a", "0x2d1f", "0x2d2b", "0x27a5", "0x27f0", "0x0F4F", "0x0F50", "0x13B1", "0x13B2");
// Tier 3: Maces,  Mauls,  Cutlasses, Viking Swords,War Maces, Longswords
const tier3weapons = new Array( "0x0F5C", "0x0F5D", "0x143A", "0x143B", "0x1440", "0x1441", "0x13B9", "0x13BA", "0x1406", "0x1407", "0x0F60", "0x0F61", "0x13B7", "0x13B8" );
// Tier 4: War Axes, Axes, Gnarled Staffs, Executioner's Axes, Scimitars, Battle Axes, Large Battle Axes, Broad Swords, Bardiches, Two-Handed Axes, Black Staves, War Forks, War Hammers
const tier4weapons = new Array( "0x13AF", "0x13B0", "0x0F49", "0x0F4A", "0x13F8", "0x13F9", "0x0F45", "0x0F46", "0x13B5", "0x13B6", "0x0F47", "0x0F48", "0x13FA", "0x13FB", "0x0F5E", "0x0F5F", "0x0F4D", "0x0F4E", "0x1442", "0x1443", "0x0DF0", "0x0DF1", "0x1404", "0x1405", "0x1438", "0x1439" );
// Tier 5: Krysses, Quarterstaves, Spears, Double Axes, Short Spears, Halberds, Katanas
const tier5weapons = new Array( "0x1400", "0x1401", "0x0E89", "0x0E8A", "0x0F62", "0x0F63", "0x0F4B", "0x0F4C", "0x1402", "0x1403", "0x143E", "0x143F", "0x13FE", "0x13FF" );

//Leather/Studded Leather + buckler
const tier1armors = new Array( "0x13c5", "0x13c6", "0x13c7", "0x13cb", "0x13cc", "0x13cd", "0x13ce", "0x13d2", "0x13d3", "0x13d4",
                            "0x13d5", "0x13d6", "0x13da", "0x13db", "0x13dc", "0x13dd", "0x13e1", "0x13e2", "0x1c00", "0x1c06",
                            "0x1c08", "0x1c0a", "0x1c02", "0x1c0c", "0x1b73" );
//Ringmail + wooden shield, metal shield
const tier2armors = new Array( "0x13eb", "0x13ec", "0x13ed", "0x13ee", "0x13ef", "0x13f0", "0x13f1", "0x13f2", "0x1b7a", "0x1b7b" );
//Chainmail + bronze shield, wooden kite shield
const tier3armors = new Array( "0x13bb", "0x13be", "0x13bf", "0x13c0", "0x13c3", "0x13c4", "0x1b72", "0x1b78", "0x1b79" );
//Bone + metal kite shield
const tier4armors = new Array( "0x144e", "0x144f", "0x1450", "0x1451", "0x1452", "0x1453", "0x1454", "0x1455", "0x1456", "0x1457", "0x1b74", "0x1b75" );
//Plate + heater shield
const tier5armors = new Array( "0x1410", "0x1411", "0x1412", "0x1413", "0x1414", "0x1415", "0x1416", "0x1417", "0x1418", "0x1419", "0x141a", "0x1c04", "0x1b76", "0x1b77" );

// Footwear
const tier1clothing = new Array( "0x170b", "0x170d", "0x170f", "0x1711" );
// Clothing
const tier2clothing = new Array( "0x1541", "0x1515", "0x1f7b", "0x1eff", "0x1efd", "0x153d", "0x153b", "0x1f9f", "0x1537", "0x1539", "0x1f01", "0x1f03", "0x1517", "0x152e", "0x1531", "0x1fa1", "0x1ffd" );

// Magic Wands and gnarled staffs
const magicWands = new Array( "0x0df2", "0x0df3", "0x0df4", "0x0df5", "0x13f8", "0x13f9" );

// (Potentially) create magic item on corpse upon death
function onDeath( cNpc, iCorpse )
{
    // Double check that both NPC and corpse exist - they should,
    // as this script runs before the dead NPC is cleaned up
    if( !ValidateObject( cNpc ) || !ValidateObject( iCorpse ))
        return false;

    // Only trigger script if NPC has enough fame to actually own a magical item
    var npcFame = cNpc.fame;
    if( npcFame >= 1000 )
    {
        // Determine max amount of magic items that can potentially spawn for a given NPC
        var maxItemAmount = 0;
        if( npcFame < 3000 )
            maxItemAmount = 1;
        else if( npcFame < 6000 )
            maxItemAmount = 2;
        else if( npcFame < 8000 )
            maxItemAmount = 3;
        else if( npcFame < 10000 )
            maxItemAmount = 5;
        else if( npcFame < 15000 )
            maxItemAmount = 6;
        else
            maxItemAmount = 7;

        for( var i = 0; i < maxItemAmount; i++ )
        {
            // Run the chance calculator to determine chance of item being spawned
            var spawnMagicItem = MagicLootChanceCalculator( npcFame, false );

            if( spawnMagicItem )
            {
                // Determine what type of magic loot to create
                itemType = weightedRandom( 1, 5 );
                switch( itemType )
                {
                    case 1: // Weapon
                    case 2: // Armor
                        itemType = RandomNumber( 0, 1 );
                        break;
                    case 3: // Wand
                        itemType = 2;
                        break;
                    case 4: // Ring
                        itemType = 3;
                        break;
                    case 5: // Clothing
                        itemType = 3;
                        break;                     
                }

                // Actually create the magic loot!
                var magicItem = GenerateMagicItem( itemType, null );
                if( ValidateObject( magicItem ))
                    magicItem.container = iCorpse;
            }
        }
    }
    return false;
}

// Function that runs upon creation of dummy items with this script attached,
// with the intention of adding random magic weapons directly, either via GM command
// or as guaranteed loot in treasure chests, on boss NPCs etc
function onCreateDFN( objMade, objType )
{
    if( objType == 0 && ValidateObject( objMade ))
    {
        //Console.Log( "Object Buy Value: " + objMade.buyvalue + "  -  Object Sell Value: " + objMade.sellvalue );
        var fameLevel = objMade.morex;
        if( fameLevel == 0 )
            fameLevel = RandomNumber( 1, 10000 );

        MagicLootChanceCalculator( fameLevel, true );

        // Determine what type of magic loot to create. If morex of dummy object is 5,
        // randomize the type of item to create. Otherwise, use the morex value
        var itemType = objMade.morey;
        if( itemType == 5 )
        {
            itemType = weightedRandom( 0, 4 );
            switch( itemType )
            {
                case 0: // Clothing
                    itemType = 4;
                    break;
                case 1: // Weapon
                case 2: // Armor
                    itemType = RandomNumber( 0, 1 );
                    break;
                case 3: // Wand
                    itemType = 2;
                    break;
                case 4: // Jewelry
                    itemType = 3;
                    break;
            }
        }

        // Actually create the magic loot, and place it in the target Container
        var magicItem = GenerateMagicItem( itemType, objMade );

        // Delete the newly created magicItem, since we only used it as a temporary item and copied
        // all its properties to objMade already
        if( ValidateObject( magicItem ))
            magicItem.Delete();
    }
}

// Run chance calculator to determine if magical loot should be generated, and if so, what tier
var maxTierLevel = 0;
function MagicLootChanceCalculator( fameLevel, guaranteedLoot )
{
    var dropRateNum = 0;
    if( fameLevel <= tier1NPCFame )
    {
        maxTierLevel = 1;
        dropRateNum = Math.round( tier1DropRate / globalDropRateMod );
    }
    else if( fameLevel > tier1NPCFame && fameLevel <= tier2NPCFame )
    {
        maxTierLevel = 2;
        dropRateNum = Math.round( tier2DropRate / globalDropRateMod );
    }
    else if( fameLevel > tier2NPCFame && fameLevel <= tier3NPCFame )
    {
        maxTierLevel = 3;
        dropRateNum = Math.round( tier3DropRate / globalDropRateMod );
    }
    else if( fameLevel > tier3NPCFame && fameLevel <= tier4NPCFame )
    {
        maxTierLevel = 4;
        dropRateNum = Math.round( tier4DropRate / globalDropRateMod );
    }
    else if( fameLevel > tier4NPCFame )
    {
        maxTierLevel = 5;
        dropRateNum = Math.round( tier5DropRate / globalDropRateMod );
    }

    // Time to do a check to see if we should spawn a magic item or not
    var iNum = RandomNumber( 0, dropRateNum );
    if( iNum == dropRateNum )
        return true; // success!
    else
        return false; // no such luck
}

// Generate a magic item of specified itemType (weapon, armor) based on a given fame level. targCont is container to put item in
function GenerateMagicItem( itemType, placeHolderItem )
{
    // Console.Log("Item Type: " + itemType);
    // Let's figure out which tier of magic weapons to potentially spawn from
    //var tierNum = RandomNumber( 1, maxTierLevel );
    var tierNum = maxTierLevel;

    // Let's put in a small chance of getting an item from a higher tier
    tierNum = calcTierBonus( tierNum );

    // Time to create the magic item itself
    var magicItem;
    switch( itemType )
    {
        case 0: // magic weapon
            magicItem = CreateMagicWeapon( tierNum, placeHolderItem );
            break;
        case 1: // magic armor
            magicItem = CreateMagicArmor( tierNum, placeHolderItem );
            break;
        case 2: // magic wand/staff
            magicItem = CreateMagicWand( tierNum, placeHolderItem );
            break;
        case 3: // magic jewlery
            magicItem = CreateMagicJewelry( tierNum, placeHolderItem );
            break;
        case 4: // magic clothes
            magicItem = CreateMagicClothes( tierNum, placeHolderItem );
            break;
        default:
            Console.Error("Creation of undefined magic item type of " + itemType + "failed in GenerateMagicItem");
            break;
    }

    // Return the magic item we created!
    return magicItem;
}

function calcTierBonus( tierVal )
{
    if( tierVal < 5 )
    {
        var bonusChance = RandomNumber( 0, 1000 );
        var tierValBonus = 0;

        switch( tierVal )
        {
            case 1:
                if( bonusChance >= 999 ) // 0.1% chance
                {
                    tierValBonus = 4;
                }
                else if( bonusChance >= 998 ) // 0.2% chance
                {
                    tierValBonus = 3;
                }
                else if( bonusChance >= 996 ) // 0.4% chance
                {
                    tierValBonus = 2;
                }
                else if( bonusChance >= 992 ) // 0.8% chance
                {
                    tierValBonus = 1;
                }
                break;
            case 2:
                if( bonusChance >= 998 ) // 0.2% chance
                {
                    tierValBonus = 3;
                }
                else if( bonusChance >= 996 ) // 0.4% chance
                {
                    tierValBonus = 2;
                }
                else if( bonusChance >= 992 ) // 0.8% chance
                {
                    tierValBonus = 1;
                }
                break;
            case 3:
                if( bonusChance >= 996 ) // 0.4% chance
                {
                    tierValBonus = 2;
                }
                else if( bonusChance >= 992 ) // 0.8% chance
                {
                    tierValBonus = 1;
                }
                break;
            case 4:
                if( bonusChance >= 992 ) // 0.8% chance
                {
                    tierValBonus = 1;
                }
                break;
        }

        tierVal += tierValBonus;
    }

    return tierVal;
}

// ----------------------
// CREATE MAGICAL WEAPON
// ----------------------

function CreateMagicWeapon( tierNum, placeHolderItem )
{
    // Create random Weapon from chosen tier
    var rndWeapon;
    var rndWeaponNum;
    switch( tierNum )
    {
        case 1:
            rndWeaponNum = RandomNumber( 0, tier1weapons.length - 1 );
            rndWeapon = CreateDFNItem( null, null, tier1weapons[rndWeaponNum], 1, "ITEM", false );
            break;
        case 2:
            rndWeaponNum = RandomNumber( 0, tier2weapons.length - 1 );
            rndWeapon = CreateDFNItem( null, null, tier2weapons[rndWeaponNum], 1, "ITEM", false );
            break;
        case 3:
            rndWeaponNum = RandomNumber( 0, tier3weapons.length - 1 );
            rndWeapon = CreateDFNItem( null, null, tier3weapons[rndWeaponNum], 1, "ITEM", false );
            break;
        case 4:
            rndWeaponNum = RandomNumber( 0, tier4weapons.length - 1 );
            rndWeapon = CreateDFNItem( null, null, tier4weapons[rndWeaponNum], 1, "ITEM", false );
            break;
        case 5:
            rndWeaponNum = RandomNumber( 0, tier5weapons.length - 1 );
            rndWeapon = CreateDFNItem( null, null, tier5weapons[rndWeaponNum], 1, "ITEM", false );
            break;
        default:
            Console.Error( "Unable to spawn magic item - switch case in SpawnMagicWeapon out of bounds!" );
            break;
    }

    if( !ValidateObject( rndWeapon ))
    {
        Console.Error( "Unable to spawn DFN item from tier-array " + tierNum + " with array-position (rndWeaponNum) " + rndWeaponNum );
        return null;
    }

    // Handle weapon bonuses
    // Time to add some bonuses: HP bonus, an ACCURACY bonus, a DAMAGE bonus - or combinations of two/all three
    var rndBonus = RandomNumber( 1, 100 );

    // Increase rndBonus by 2.5 to 12.5 depending on maxTierLevel of NPC, so the higher the
    // maxTierLevel, the better chance of getting a non-rubbish magical item!
    rndBonus = rndBonus + ( Math.round( maxTierLevel * 2.5 ));
    rndBonus = Math.round( rndBonus );

    // Buy value varies on added abilities
    var baseWeaponValue = placeHolderItem.buyvalue;
    rndWeapon.buyvalue = placeHolderItem.buyvalue;


    var addHpBonus = false;
    var addAccBonus = false;
    var addDmgBonus = false;
    var addSilverBonus = false;

    if( rndBonus >= 0 && rndBonus < 70 )
    {
        // 1 Magical Effect
        rndBonus = RandomNumber( 0, 3 );
        if( rndBonus == 0 )
            addHpBonus = true;
        else if( rndBonus == 1 )
            addAccBonus = true;
        else if( rndBonus == 2 )
            addDmgBonus = true;
        else if( rndBonus == 3 )
            addSilverBonus = true;
    }
    else if( rndBonus >= 70 && rndBonus < 99 )
    {
        // 2 Magical Effects
        rndBonus = RandomNumber( 0, 5 );
        if( rndBonus == 0 )
        {
            addHpBonus = true;
            addAccBonus = true;
        }
        else if( rndBonus == 1 )
        {
            addHpBonus = true;
            addDmgBonus = true;
        }
        else if( rndBonus == 2 )
        {
            addAccBonus = true;
            addDmgBonus = true;
        }
        else if( rndBonus == 3 )
        {
            addHpBonus = true;
            addSilverBonus = true;
        }
        else if( rndBonus == 4 )
        {
            addAccBonus = true;
            addSilverBonus = true;
        }
        else if( rndBonus == 5 )
        {
            addDmgBonus = true;
            addSilverBonus = true;
        }
    }
    else if( rndBonus >= 99 && rndBonus < 110 )
    {
        // 3 Magical Effects
        rndBonus = RandomNumber( 0, 3 );
        if( rndBonus == 0 )
        {
            addHpBonus = true;
            addAccBonus = true;
            addDmgBonus = true;
        }
        else if( rndBonus == 1 )
        {
            addHpBonus = true;
            addAccBonus = true;
            addSilverBonus = true;
        }
        else if( rndBonus == 2 )
        {
            addHpBonus = true;
            addDmgBonus = true;
            addSilverBonus = true;
        }
        else if( rndBonus == 3 )
        {
            addAccBonus = true;
            addDmgBonus = true;
            addSilverBonus = true;
        }
    }
    else if( rndBonus >= 110 )
    {
        // 4 Magical Effects
        addHpBonus = true;
        addAccBonus = true;
        addDmgBonus = true;
        addSilverBonus = true;
    }

    // Grab a copy of the original name of the item, so we have it for later
    var tempName = rndWeapon.name;
    rndWeapon.name2 = "";

    // Are we adding HP bonuses?
    if( addHpBonus )
    {
        calcHpBonus( rndWeapon, 0 );
        rndWeapon.buyvalue += baseWeaponValue;
    }

    // Are we adding ACC bonuses?
    if( addAccBonus )
    {
        calcAccuracyBonus( rndWeapon, addHpBonus );
        rndWeapon.buyvalue += baseWeaponValue;
    }
    else if( addHpBonus )
    {
        rndWeapon.name2 += " ";
    }

    // Add Silver bonus?
    if( addSilverBonus )
    {
        rndWeapon.name2 += "silver ";
        rndWeapon.race = 11;
        rndWeapon.buyvalue += baseWeaponValue;
    }

    // Add item-name after HP and ACC bonuses, but before a potential DMG bonus
    rndWeapon.name2 += tempName;

    // Are we adding Damage bonuses?
    if( addDmgBonus )
    {
        rndWeapon.name2 += " of ";
        calcDamageBonus( rndWeapon );
        rndWeapon.buyvalue += baseWeaponValue;     
    }

    // Are we adding Spell bonuses?
    iNum = RandomNumber( 1, 100 );
    if( iNum <= 5 ) // 5% chance of spell bonus for a given magical weapon
    {
        if( addDmgBonus )
        {
            rndWeapon.name2 += " and ";
        }
        else
        {
            rndWeapon.name2 += " of ";
        }

        calcWeaponSpellBonus( rndWeapon );
        rndWeapon.buyvalue *= 2;
    }

    rndWeapon.name = "a magic " + tempName;

    // Is final name too long? Not much we can do about it, MAX_NAME in UOX3 code is set to 128... Log it anyway, though.
    if( rndWeapon.name2.length >= 128 )
    {
        Console.Log( "Magic item generated with name consisting of 128 or more letters! Serial: " + rndWeapon.serial + ", length: " + rndWeapon.name2.length );
    }

    if( outputMagicItemNamesToFile )
        addToDatabase( 0, rndWeapon.name2 );

    if( ValidateObject( rndWeapon ) && ValidateObject( placeHolderItem ))
    {
        // Loop through all the properties for our new magic item and copy them over to the placeholder item
        for( var itemProp in rndWeapon )
        {
            if( itemProp != null && itemProp != "serial" && itemProp != "scripttrigger" && itemProp != "scriptTriggers"
                    && itemProp != "sellvalue" && itemProp != "restock")
            {
                if( typeof( rndWeapon[itemProp] ) != "undefined" && rndWeapon[itemProp] != null )
                {
                    if( itemProp == "race" && rndWeapon.race != null )
                        placeHolderItem.race = rndWeapon.race.id;
                    else
                    {
                        placeHolderItem[itemProp] = rndWeapon[itemProp];
                    }
                }
            }
        }

        // Copy scripttriggers too!
        var scriptTriggerList = rndWeapon.scriptTriggers;
        for( var i = 0; i < scriptTriggerList.length; i++ )
        {
            if( scriptTriggerList[i] != 0 && scriptTriggerList[i] != magicItemScriptID )
                placeHolderItem.AddScriptTrigger( scriptTriggerList[i] );
        }

        // Set accBonus tag too!
        if( rndWeapon.GetTag( "accBonus" ))
            placeHolderItem.SetTag( "accBonus", rndWeapon.GetTag( "accBonus" ));
    }
    return rndWeapon;
}

function calcHpBonus( rndItem, itemType )
{
    // Define some variables
    var hpBonus = 0;
    var hpBonusName = "";

    // Let's put in a small chance of getting a better bonus
    maxTierLevel = calcTierBonus( maxTierLevel );

    // Which bonus-tier are we adding, exactly?
    var bonusTier = RandomNumber( 1, maxTierLevel );

    switch( bonusTier )
    {
        case 1:
            hpBonus = 10;
            hpBonusName = "durable";
            break;
        case 2:
            hpBonus = 20;
            hpBonusName = "reinforced";
            break;
        case 3:
            hpBonus = 30;
            hpBonusName = "substantial";
            break;
        case 4:
            hpBonus = 40;
            hpBonusName = "fortified";
            break;
        case 5:
            hpBonus = 50;
            hpBonusName = "indestructable";
            break;
    }

    // if itemType is armor, halve the hp bonus
    if( itemType == 1 )
        hpBonus /= 2;

    // Let's add that bonus and adjust the weapon's magical name accordingly
    rndItem.maxhp += hpBonus;
    rndItem.health = rndItem.maxhp;
    rndItem.name2 += hpBonusName;
}

function calcAccuracyBonus( rndWeapon, addHpBonus )
{   // Let's add some Weapon Bonuses! (Bonii?)

    // Define some variables
    var accBonus = 0;
    var accBonusArchery = 0;
    var accBonusName = "";

    // Let's put in a small chance of getting a better bonus
    maxTierLevel = calcTierBonus( maxTierLevel );

    // Which bonus-tier are we adding, exactly?
    var bonusTier = RandomNumber( 1, maxTierLevel );

    //Note that for the bonuses, 50 equals 5.0 skillpoints, 200 equals 20.0 skillpoints, etc.
    switch( bonusTier )
    {
        case 1:
            accBonus = 50;
            accBonusArchery = 46;
            accBonusName = "accurate";
            break;
        case 2:
            accBonus = 100;
            accBonusArchery = 93;
            accBonusName = "surpassingly accurate";
            break;
        case 3:
            accBonus = 150;
            accBonusArchery = 140;
            accBonusName = "eminently accurate";
            break;
        case 4:
            accBonus = 200;
            accBonusArchery = 187;
            accBonusName = "exceedingly accurate";
            break;
        case 5:
        case 6:
        case 7:
        default:
            accBonus = 250;
            accBonusArchery = 233;
            accBonusName = "supremely accurate";
            break;
    }

    // Let's add a bonus that will temporarily add to player skills when item is equipped
    // If ranged weapon, add to archery skill instead of tactics skill
    if( rndWeapon.id == 0x13B1 || rndWeapon.id == 0x13B2 || rndWeapon.id == 0x26C2 || rndWeapon.id == 0x26CC ||
        rndWeapon.id == 0x2571 || rndWeapon.id == 0x0F4F || rndWeapon.id == 0x0F50 || rndWeapon.id == 0x13FC ||
        rndWeapon.id == 0x13FD || rndWeapon.id == 0x26C3 || rndWeapon.id == 0x26CD || rndWeapon.id == 0x27A5 ||
        rndWeapon.id == 0x27F0 )
    {
        rndWeapon.SetTag( "accBonus", accBonusArchery );
    }
    else
    {
        rndWeapon.SetTag( "accBonus", accBonus );
    }

    // Add accuracy bonus JS-script to weapon
    rndWeapon.AddScriptTrigger( accBonusScriptID );

    // Let's add bonus-name to item
    if( addHpBonus == true )
    {
        rndWeapon.name2 += ", " + accBonusName + " ";
    }
    else
    {
        rndWeapon.name2 += accBonusName + " ";
    }
}

function calcDamageBonus( rndWeapon )
{   // Let's add some Weapon Bonuses! (Bonii?)

    // Define some variables
    var dmgBonus = 0;
    var dmgBonusName = "";

    // Let's put in a small chance of getting a better bonus
    maxTierLevel = calcTierBonus( maxTierLevel );

    // Which bonus-tier are we adding, exactly?
    var bonusTier = RandomNumber( 1, maxTierLevel );

    switch( bonusTier )
    {
        case 1:
            dmgBonus = 1;
            dmgBonusName = "ruin";
            break;
        case 2:
            dmgBonus = 3;
            dmgBonusName = "might";
            break;
        case 3:
            dmgBonus = 5;
            dmgBonusName = "force";
            break;
        case 4:
            dmgBonus = 7;
            dmgBonusName = "power";
            break;
        case 5:
            dmgBonus = 9;
            dmgBonusName = "vanquishing";
            break;
    }

    //Let's add that bonus-damage
    if( dmgBonusType = 0 )
    {
        rndWeapon.hidamage += dmgBonus;
    }
    else
    {
        rndWeapon.lodamage += ( dmgBonus / 2 );
        rndWeapon.hidamage += ( dmgBonus / 2 );
    }

    // Let's add the bonus-name
    rndWeapon.name2 += dmgBonusName;
}

function calcWeaponSpellBonus( rndWeapon )
{
    // Define some variables
    var spellBonusName = "";
    var spellCircle = 0;
    var spellNumber = 0;
    var spellCharges = 0;

    // Let's put in a small chance of getting a better bonus
    maxTierLevel = calcTierBonus( maxTierLevel );

    // Which bonus-tier are we adding, exactly?
    var bonusTier = RandomNumber( 1, maxTierLevel );

    switch( bonusTier )
    {
        case 1:
            spellCircle = 1;
            var iNum = RandomNumber( 0, 2 );
            if( iNum == 0 )
            {
                spellBonusName = "Clumsiness";
                spellNumber = 1;
                spellCharges = RandomNumber( 25, 50 );
            }
            else if( iNum == 1 )
            {
                spellBonusName = "Feeblemindedness";
                spellNumber = 3;
                spellCharges = RandomNumber( 25, 50 );
            }
            else
            {
                spellBonusName = "Weakness";
                spellNumber = 8;
                spellCharges = RandomNumber( 25, 50 );
            }
            break;
        case 2:
            var iNum = RandomNumber( 0, 100 );
            if( iNum < 45 ) // 45% chance
            {
                spellBonusName = "Burning"; // Magic Arrow
                spellCircle = 1;
                spellNumber = 5;
                spellCharges = RandomNumber( 25, 50 );
            }
            else if( iNum < 80 ) // 35% chance
            {
                spellBonusName = "Wounding"; // Harm
                spellCircle = 2;
                // spellNumber = 4;
                spellNumber = 12;
                spellCharges = RandomNumber( 25, 50 );
            }
            else // 20% chance
            {
                spellBonusName = "Daemon's Breath"; // Fireball
                spellCircle = 3;
                // spellNumber = 2;
                spellNumber = 18;
                spellCharges = RandomNumber( 25, 50 );
            }
            break;
        case 3:
            spellCircle = 4;
            var iNum = RandomNumber( 0, 1 );
            if( iNum == 0 )
            {
                spellBonusName = "Mages Bane"; // Mana Drain
                // spellNumber = 7;
                spellNumber = 31;
                spellCharges = RandomNumber( 25, 50 );
            }
            else
            {
                spellBonusName = "Evil"; // Curse
                // spellNumber = 3;
                spellNumber = 27;
                spellCharges = RandomNumber( 25, 50 );
            }
            break;
        case 4:
            spellBonusName = "Thunder"; // Lightning
            spellCircle = 4;
            // spellNumber = 6;
            spellNumber = 30;
            spellCharges = RandomNumber( 25, 50 );
            break;
        case 5:
            spellBonusName = "Ghoul's Touch"; // Paralyze
            spellCircle = 5;
            // spellNumber = 6;
            spellNumber = 38;
            spellCharges = RandomNumber( 25, 50 );
            break;
    }

    //Let's add that bonus-spell
    rndWeapon.type = 15;
    rndWeapon.AddScriptTrigger( magicWeaponSpellScriptID );
    rndWeapon.morex = spellCircle;
    rndWeapon.morey = spellNumber;
    rndWeapon.morez = spellCharges;

    // Let's add the bonus-name
    rndWeapon.name2 += spellBonusName;
}

// ---------------------
// CREATE MAGICAL ARMOR
// ---------------------

function CreateMagicArmor( tierNum, placeHolderItem )
{
    // Create random item from chosen tier
    var rndArmor;
    var rndArmorNum;
    switch( tierNum )
    {
        case 1:
            rndArmorNum = RandomNumber( 0, tier1armors.length - 1);
            rndArmor = CreateDFNItem( null, null, tier1armors[rndArmorNum], 1, "ITEM", false );
            break;
        case 2:
            rndArmorNum = RandomNumber( 0, tier2armors.length - 1);
            rndArmor = CreateDFNItem( null, null, tier2armors[rndArmorNum], 1, "ITEM", false );
            break;
        case 3:
            rndArmorNum = RandomNumber( 0, tier3armors.length - 1);
            rndArmor = CreateDFNItem( null, null, tier3armors[rndArmorNum], 1, "ITEM", false );
            break;
        case 4:
            rndArmorNum = RandomNumber( 0, tier4armors.length - 1 );
            rndArmor = CreateDFNItem( null, null, tier4armors[rndArmorNum], 1, "ITEM", false );
            break;
        case 5:
            rndArmorNum = RandomNumber( 0, tier5armors.length - 1 );
            rndArmor = CreateDFNItem( null, null, tier5armors[rndArmorNum], 1, "ITEM", false );
            break;
        default:
            break;
    }

    if( !ValidateObject( rndArmor ))
    {
        Console.Error( "Unable to spawn DFN item from tier-array " + tierNum + " with array-position (rndArmorNum) " + rndArmorNum );
        return null;
    }

    // Handle armor bonuses
    // Should we add a HP bonus, an AR bonus - or both?
    var rndBonus = RandomNumber( 0, 100 );

    var addHpBonus = false;
    var addArmorBonus = false;

    // Buy value varies on added abilities
    var baseArmorValue = placeHolderItem.buyvalue;
    rndArmor.buyvalue = placeHolderItem.buyvalue;


    // Increase rndBonus by 2.5 to 12.5 extra depending on maxTierLevel of NPC, so
    // the higher the maxTierLevel, the less chance of getting rubbish magical items!
    rndBonus = rndBonus + ( Math.round( maxTierLevel * 2.5 ));
    rndBonus = Math.round( rndBonus );

    if( rndBonus >= 0 && rndBonus < 95 )
    {
        // 1 Magical Effect
        iNum = RandomNumber( 0, 1 );
        if( iNum == 0 )
        {
            //Only HP Bonus
            addHpBonus = true;
        }
        else if( iNum == 1 )
        {
            //Only AR Bonus
            addArmorBonus = true;
        }
    }
    else
    {
        // 2 Magical Effects
        addHpBonus = true;
        addArmorBonus = true;
    }

    // First store the original item-name in a tempVariable
    var tempName = rndArmor.name;
    rndArmor.name2 = "";

    // Are we adding HP bonuses?
    if( addHpBonus )
    {
        calcHpBonus( rndArmor, 1 );
        rndArmor.name2 += " ";
        rndArmor.buyvalue += baseArmorValue;
    }

    // Add item-name after HP bonus, but before a potential AR bonus
    rndArmor.name2 += tempName;

    // Are we adding AR bonuses?
    if( addArmorBonus )
    {
        calcArmorBonus( rndArmor );
        rndArmor.buyvalue += baseArmorValue;
    }

    // Are we adding spell bonuses?
    iNum = RandomNumber( 1, 100 );
    if( iNum <= 5 ) // 5% chance of spell bonus on a given magic armor
    {
        if( addArmorBonus )
        {
            rndArmor.name2 += " and ";
        }
        else
        {
            rndArmor.name2 += " of ";
        }

        calcArmorSpellBonus( rndArmor );
        rndArmor.buyvalue *= 2;
       
        // Add script that handles equip effects to the magic armor
        rndArmor.AddScriptTrigger( armorSpellsScriptID );
    }

    rndArmor.name = "magic " + tempName;

    // Is final name too long? Not much we can do about it, MAX_NAME in UOX3 code is set to 128... Log it anyway, though.
    if( rndArmor.name2.length >= 128 )
    {
        Console.Log( "Magic armor generated with name consisting of 128 or more letters! Serial: " + rndArmor.serial );
    }

    if( outputMagicItemNamesToFile )
        addToDatabase( 1, rndArmor.name2 );

    if( ValidateObject( rndArmor ) && ValidateObject( placeHolderItem ))
    {
        // Loop through all the properties for our new magic item and copy them over to the placeholder item
        for( var itemProp in rndArmor )
        {
            if( itemProp != null && itemProp != "serial" && itemProp != "scripttrigger" && itemProp != "scriptTriggers"
                    && itemProp != "sellvalue" && itemProp != "restock" )
            {
                if( typeof( rndArmor[itemProp] ) != "undefined" && rndArmor[itemProp] != null )
                {
                    if( itemProp == "race" && rndArmor.race != null )
                        placeHolderItem.race = rndArmor.race.id;
                    else
                    {
                        placeHolderItem[itemProp] = rndArmor[itemProp];
                    }
                }
            }
        }

        // Copy scripttriggers too!
        var scriptTriggerList = rndArmor.scriptTriggers;
        for( var i = 0; i < scriptTriggerList.length; i++ )
        {
            if( scriptTriggerList[i] != 0 && scriptTriggerList[i] != magicItemScriptID )
                placeHolderItem.AddScriptTrigger( scriptTriggerList[i] );
        }
    }
    return rndArmor;
}

function calcArmorBonus( rndArmor )
{
    // Define some variables
    var arBonus = 0;
    var arBonusName = "";

    // Let's put in a small chance of getting a better bonus
    maxTierLevel = calcTierBonus( maxTierLevel );

    // Which bonus-tier are we adding, exactly?
    var bonusTier = RandomNumber( 1, maxTierLevel );

    switch( bonusTier )
    {
        case 1:
            arBonus = 5;
            arBonusName = "of defense";
            break;
        case 2:
            arBonus = 10;
            arBonusName = "of guarding";
            break;
        case 3:
            arBonus = 15;
            arBonusName = "of hardening";
            break;
        case 4:
            arBonus = 20;
            arBonusName = "of fortification";
            break;
        case 5:
        case 6:
        case 7:
        default:
            arBonus = 25;
            arBonusName = "of invulnerability";
            break;
    }

    //Let's add that bonus and change the name
    var defRating = rndArmor.Resist( 1 );
    defRating += arBonus;
    rndArmor.Resist( 1, defRating );
    rndArmor.name2 += " " + arBonusName;
}

function calcArmorSpellBonus( rndArmor )
{
    // Define some variables
    var spellBonusName = "";
    var spellCircle = 0;
    var spellNumber = 0;
    var spellCharges = 0;

    // Let's put in a small chance of getting a better bonus
    maxTierLevel = calcTierBonus( maxTierLevel );

    // Which bonus-tier are we adding, exactly?
    var bonusTier = RandomNumber( 1, maxTierLevel );

    var rndNum = 0;
    switch( bonusTier )
    {
        case 1:
            rndNum = RandomNumber( 0, 100 );
            if( rndNum <= 25 ) // 25% chance
            {
                spellBonusName = "Clumsiness";
                spellCircle = 1;
                spellNumber = 1;
                spellCharges = RandomNumber( 5, 30 );
            }
            else if( rndNum <= 50 ) // 25% chance
            {
                spellBonusName = "Feeblemindedness";
                spellCircle = 1;
                spellNumber = 3;
                spellCharges = RandomNumber( 5, 30 );
            }
            else if( rndNum <= 75 ) // 25% chance
            {
                spellBonusName = "Weakness";
                spellCircle = 1;
                spellNumber = 8;
                spellCharges = RandomNumber( 5, 30 );
            }
            else if( rndNum <= 80 ) // 5% chance
            {
                spellBonusName = "Might";
                spellCircle = 2;
                spellNumber = 16;
                spellCharges = RandomNumber( 5, 25 );
            }
            else if( rndNum <= 85 ) // 5% chance
            {
                spellBonusName = "Cunning";
                spellCircle = 2;
                spellNumber = 10;
                spellCharges = RandomNumber( 5, 25 );
            }
            else if( rndNum <= 90 ) // 5% chance
            {
                spellBonusName = "Agility";
                spellCircle = 2;
                spellNumber = 19
                spellCharges = RandomNumber( 5, 25 );
            }
            else  // 10% chance
            {
                spellBonusName = "Feline Eyes";
                spellCircle = 1;
                spellNumber = 6;
                spellCharges = RandomNumber( 5, 30 );
            }
            break;
        case 2:
            rndNum = RandomNumber( 0, 100 );
            if( rndNum <= 10 ) // 10% chance
            {
                spellBonusName = "Clumsiness";
                spellCircle = 1;
                spellNumber = 1;
                spellCharges = RandomNumber( 5, 30 );
            }
            else if( rndNum <= 20 ) // 10% chance
            {
                spellBonusName = "Feeblemindedness";
                spellCircle = 1;
                spellNumber = 3;
                spellCharges = RandomNumber( 5, 30 );
            }
            else if( rndNum <= 30 ) // 10% chance
            {
                spellBonusName = "Weakness";
                spellCircle = 1;
                spellNumber = 8;
                spellCharges = RandomNumber( 5, 30 );
            }
            else if( rndNum <= 50 ) // 20% chance
            {
                spellBonusName = "Might";
                spellCircle = 2;
                spellNumber = 16;
                spellCharges = RandomNumber( 5, 25 );
            }
            else if( rndNum <= 70 ) // 20% chance
            {
                spellBonusName = "Cunning";
                spellCircle = 2;
                spellNumber = 10;
                spellCharges = RandomNumber( 5, 25 );
            }
            else if( rndNum <= 90 ) // 20% chance
            {
                spellBonusName = "Agility";
                spellCircle = 2;
                spellNumber = 19
                spellCharges = RandomNumber( 5, 25 );
            }
            else  // 10% chance
            {
                spellBonusName = "Feline Eyes";
                spellCircle = 1;
                spellNumber = 6;
                spellCharges = RandomNumber( 5, 30 );
            }
            break;
        case 3:
            rndNum = RandomNumber( 0, 100 );
            if( rndNum <= 5 ) // 5% chance
            {
                spellBonusName = "Clumsiness";
                spellCircle = 1;
                spellNumber = 1;
                spellCharges = RandomNumber( 5, 30 );
            }
            else if( rndNum <= 10 ) // 5% chance
            {
                spellBonusName = "Feeblemindedness";
                spellCircle = 1;
                spellNumber = 3;
                spellCharges = RandomNumber( 5, 30 );
            }
            else if( rndNum <= 15 ) // 5% chance
            {
                spellBonusName = "Weakness";
                spellCircle = 1;
                spellNumber = 8;
                spellCharges = RandomNumber( 5, 30 );
            }
            else if( rndNum <= 40 ) // 25% chance
            {
                spellBonusName = "Strength";
                spellCircle = 2;
                spellNumber = 16;
                spellCharges = RandomNumber( 5, 25 );
            }
            else if( rndNum <= 65 ) // 25% chance
            {
                spellBonusName = "Cunning";
                spellCircle = 2;
                spellNumber = 10;
                spellCharges = RandomNumber( 5, 25 );
            }
            else if( rndNum <= 90 ) // 25% chance
            {
                spellBonusName = "Agility";
                spellCircle = 2;
                spellNumber = 19
                spellCharges = RandomNumber( 5, 25 );
            }
            if( rndNum <= 95 ) // 5% chance
            {
                spellBonusName = "Protection";
                spellCircle = 2;
                spellNumber = 5;
                spellCharges = RandomNumber( 5, 25 );
            }
            else // 5% chance
            {
                spellBonusName = "Curse";
                spellCircle = 4;
                spellNumber = 27;
                spellCharges = RandomNumber( 5, 20 );
            }
            break;
        case 4:
            rndNum = RandomNumber( 0, 100 );
            if( rndNum <= 45 ) // 45% chance
            {
                spellBonusName = "Protection";
                spellCircle = 2;
                spellNumber = 5;
                spellCharges = RandomNumber( 5, 30 );
            }
            if( rndNum <= 90 ) // 45% chance
            {
                spellBonusName = "Blessing";
                spellCircle = 3;
                spellNumber = 4;
                spellCharges = RandomNumber( 5, 25 );
            }
            else // 10% chance
            {
                spellCircle = 4;
                spellBonusName = "Curse";
                spellNumber = 27;
                spellCharges = RandomNumber( 5, 20 );
            }
            break;
        case 5:
            rndNum = RandomNumber( 0, 100 );
            if( rndNum <= 45 ) // 40% chance
            {
                spellBonusName = "Spell Reflection";
                spellCircle = 5;
                spellNumber = 36;
                spellCharges = RandomNumber( 5, 15 );
            }
            else if( rndNum <= 45 ) //40% chance
            {
                spellBonusName = "Invisibility";
                spellCircle = 6;
                spellNumber = 44;
                spellCharges = RandomNumber( 5, 10 );
            }
            else // 10% chance
            {
                spellBonusName = "Cursing";
                spellCircle = 4;
                spellNumber = 27;
                spellCharges = RandomNumber( 5, 20 );
            }
            break;
        default:
            // Fallback, just in case...
            spellBonusName = "Feline Eyes";
            spellCircle = 1;
            spellNumber = 6;
            spellCharges = RandomNumber( 5, 30 );
            break;
    }

    //Let's add that bonus-spell
    rndArmor.type = 15;
    rndArmor.morex = spellCircle;
    rndArmor.morey = spellNumber;
    rndArmor.morez = spellCharges;

    // Let's add the bonus-name
    rndArmor.name2 += spellBonusName;
}

// ----------------------
// CREATE MAGICAL WANDS/STAVES
// ----------------------

function CreateMagicWand( tierNum, placeHolderItem )
{
    // Create random wand or staff
    var rndWand;
    var rndWandNum;

    // Create a magic wand or staff
    rndWandNum = RandomNumber( 0, magicWands.length - 1 );
    rndWand = CreateDFNItem( null, null, magicWands[rndWandNum], 1, "ITEM", false );

    if( !ValidateObject( rndWand ))
    {
        Console.Error( "Unable to spawn DFN item from magic wand/staff array with array-position (rndWandNum) " + rndWandNum );
        return null;
    }

    // Grab a copy of the original name of the item, so we have it for later
    var tempName = rndWand.name;
    rndWand.name2 = rndWand.name;

    rndWand.name2 += " of ";
    calcWandSpellBonus( rndWand );

    rndWand.name = "magic " + tempName;

    // Is final name too long? Not much we can do about it, MAX_NAME in UOX3 code is set to 128... Log it anyway, though.
    if( rndWand.name2.length >= 128 )
    {
        Console.Log( "Magic item generated with name consisting of 128 or more letters! Serial: " + rndWand.serial + ", length: " + rndWand.name2.length );
    }

    if( outputMagicItemNamesToFile )
        addToDatabase( 0, rndWand.name2 );

    if( ValidateObject( rndWand ) && ValidateObject( placeHolderItem ))
    {
        // Loop through all the properties for our new magic item and copy them over to the placeholder item
        for( var itemProp in rndWand )
        {
//          Console.Log( "Property name: " + itemProp + "  -  Set to: " + rndWand[itemProp] );
            if( itemProp != null && itemProp != "serial" && itemProp != "scripttrigger" && itemProp != "scriptTriggers"
                    && itemProp != "sellvalue" && itemProp != "buyvalue" && itemProp != "restock")
            {
                if( typeof( rndWand[itemProp] ) != "undefined" && rndWand[itemProp] != null )
                {
                    if( itemProp == "race" && rndWand.race != null )
                        placeHolderItem.race = rndWand.race.id;
                    else
                    {
                        placeHolderItem[itemProp] = rndWand[itemProp];
                    }
                }
            }
        }

        // Copy scripttriggers too!
        var scriptTriggerList = rndWand.scriptTriggers;
        for( var i = 0; i < scriptTriggerList.length; i++ )
        {
            if( scriptTriggerList[i] != 0 && scriptTriggerList[i] != magicItemScriptID )
                placeHolderItem.AddScriptTrigger( scriptTriggerList[i] );
        }
    }
    return rndWand;
}

// Weighted randomizer for quick and easy randomization where lower scores have higher weights than higher ones
function weightedRandom( min, max )
{
    return Math.round(max / ( Math.random() * max + min ));
}

function calcWandSpellBonus( rndWand )
{
    // Define some variables
    var spellBonusName = "";
    var spellCircle = 0;
    var spellNumber = 0;
    var spellCharges = 0;

    // Let's put in a small chance of getting a better bonus
    maxTierLevel = calcTierBonus( maxTierLevel );

    // Which bonus-tier are we adding, exactly?
    // var bonusTier = weightedRandom( 1, maxTierLevel );
    var bonusTier = maxTierLevel;

    switch( bonusTier )
    {
        case 1: // Tier 1 - Item ID, Heal, Create Food
            spellCircle = 1;
            spellCharges = RandomNumber( 85, 100 );
            var iNum = RandomNumber( 0, 4 );
            if( iNum == 0 ) // 50%, or 13/26
            {
                spellBonusName = "Identification";
                spellNumber = 65;
            }
            else if( iNum == 1 )
            {
                spellBonusName = "Healing";
                spellCircle = 1;
                spellNumber = 4;
            }
            else if( iNum == 2 )
            {
                spellBonusName = "Create Food";
                spellCircle = 1;
                spellNumber = 2;
            }
            else if ( iNum == 3 )
            {
                spellBonusName = "Focused Casting";
                spellCircle = 2;
                spellNumber = 15;              
            }
            else
            {
                spellBonusName = "Physical Resistance";
                spellCircle = 1;
                spellNumber = 7;
            }
            break;
        case 2: // Tier 2 - Clumsy, Feeblemind, Weaken, Magic Untrap, Cure
            spellCircle = 1;
            spellCharges = RandomNumber( 75, 95 );
            var iNum = RandomNumber( 0, 4 );
            if( iNum == 0 )
            {
                spellBonusName = "Clumsiness";
                spellCircle = 1;
                spellNumber = 1;
            }
            else if( iNum == 1 )
            {
                spellBonusName = "Feeblemindedness";
                spellCircle = 1;
                spellNumber = 3;
            }
            else if( iNum == 2 )
            {
                spellBonusName = "Removing Magical Traps";
                spellCircle = 2;
                spellNumber = 14;
            }
            else if( iNum == 3 )
            {
                spellBonusName = "Removing Poison";
                spellCircle = 2;
                spellNumber = 11;
            }
            else // 33%, or 11/33
            {
                spellBonusName = "Weakness";
                spellCircle = 1;
                spellNumber = 8;
            }
            break;
        case 3: // Tier 3 - Magic Arrow, Harm, Greater Heal, Fireball, Magic Trap
            spellCharges = RandomNumber( 65, 85 );
            var iNum = RandomNumber( 1, 100 );
            if( iNum <= 25 )
            {
                spellBonusName = "Burning"; // Magic Arrow
                spellCircle = 1;
                spellNumber = 5;
            }
            else if( iNum <= 50 )
            {
                spellBonusName = "Wounding"; // Harm
                spellCircle = 2;
                spellNumber = 12;
            }
            else if( iNum <= 75 )
            {
                spellBonusName = "Greater Healing"; // Greater Heal
                spellCircle = 4;
                spellNumber = 29;
            }
            else if( iNum <= 90 )
            {
                spellBonusName = "Magical Traping"; // Greater Heal
                spellCircle = 2;
                spellNumber = 13;
            }
            else
            {
                spellBonusName = "Daemon's Breath"; // Fireball
                spellCircle = 3;
                spellNumber = 18;
            }
            break;
        case 4: // Tier 4 - Lightning, Mana Drain, Curse
            spellCircle = 4;
            spellCharges = RandomNumber( 55, 75 );
            var iNum = RandomNumber( 1, 100 );
            if( iNum <= 20 )
            {
                spellBonusName = "Mages Bane"; // Mana Drain
                spellCircle = 4;
                spellNumber = 31;
            }
            else if( iNum <= 40 )
            {
                spellBonusName = "Thunder"; // Lightning
                spellCircle = 4;
                spellNumber = 30;
            }
            else if( iNum <= 60 )
            {
                spellBonusName = "Cursing"; // Curse
                spellCircle = 4;
                spellNumber = 27;              
            }
            else if( iNum <= 80 )
            {
                spellBonusName = "Locking"; // Lock
                spellCircle = 3;
                spellNumber = 19;              
            }
            else
            {
                spellBonusName = "Unlocking"; // Unlock
                spellCircle = 3;
                spellNumber = 23;              
            }
            break;
        case 5: // Tier 5 - Summon Creature, Paralyze, Mind Blast, Dispel, Energy Bolt
            spellCircle = 5;
            spellCharges = RandomNumber( 45, 65 );
            var iNum = RandomNumber( 1, 100 );
            if( iNum <= 25 ) // 25% chance, or 10/32
            {
                spellNumber = 38;
                spellBonusName = "Holding"; // Paralyze
            }
            else if( iNum <= 50 ) // 25% chance, or 8/32
            {
                spellNumber = 40;
                spellBonusName = "Summon Minion";
            }
            else if( iNum <= 70 ) // 20% chance, or 7/32
            {
                spellNumber = 37;
                spellBonusName = "Psyche Assault";
            }
            else if( iNum <= 90 ) // 20% chance, or 7/32
            {
                spellNumber = 41;
                spellBonusName = "Dispelling Magic";
            }
            else  // Energy Bolt
            {
                spellNumber = 42;
                spellBonusName = "Energy Assault";
            }
            break;
    }

    //Let's add that bonus-spell
    rndWand.type = 15;
    rndWand.morex = spellCircle;
    rndWand.morey = spellNumber;
    rndWand.morez = spellCharges;

    // Let's add the bonus-name
    rndWand.name2 += spellBonusName;
}

// Debug-function to output list of names generated by script
function addToDatabase( itemType, rndItemName )
{
    var j = 0;
    var addName = true;
    var magicName = "";
    var mFileWrite = new UOXCFile();
    if( itemType == 0 ) // weapon
        mFileWrite.Open( "magicweapons_list.txt", "a" );
    else
        mFileWrite.Open( "magicarmors_list.txt", "a" );
    mFileWrite.Write( rndItemName + "\n");
    mFileWrite.Close()
    mFileWrite.Free();
}

// ---------------------
// CREATE MAGICAL Jewelry
// ---------------------

function CreateMagicJewelry( tierNum, placeHolderItem )
{
    // Create random magic jewelry
    var rndJewelry;
    var rndJewelryNum;

    // Create a ring, neckalce, earrings, or bracelet object
    if (tierNum == 1)
        rndJewelry = CreateDFNItem( null, null, "0x108a", 1, "ITEM", false );
    else if (tierNum == 2)
        rndJewelry = CreateDFNItem( null, null, "0x1088", 1, "ITEM", false );
    else if (tierNum == 3)
        rndJewelry = CreateDFNItem( null, null, "0x1087", 1, "ITEM", false );
    else if (tierNum == 4)
        rndJewelry = CreateDFNItem( null, null, "0x1086", 1, "ITEM", false );
    else
        rndJewelry = CreateDFNItem( null, null, "0x108a", 1, "ITEM", false );
   
    if( !ValidateObject( rndJewelry ))
    {
        Console.Error( "Unable to spawn magic jewlery item from DFN entry 0x108a" );
        return null;
    }

    // Grab a copy of the original name of the item, so we have it for later
    var tempName = rndJewelry.name;
    rndJewelry.name2 = rndJewelry.name;

    rndJewelry.name2 += " of ";
    calcJewelrySpellBonus( rndJewelry );

    rndJewelry.name = "a magic " + tempName;

    // Is final name too long? Not much we can do about it, MAX_NAME in UOX3 code is set to 128... Log it anyway, though.
    if( rndJewelry.name2.length >= 128 )
    {
        Console.Log( "Magic item generated with name consisting of 128 or more letters! Serial: " + rndRing.serial + ", length: " + rndRing.name2.length );
    }

    if( outputMagicItemNamesToFile )
        addToDatabase( 0, rndJewelry.name2 );

    if( ValidateObject( rndJewelry ) && ValidateObject( placeHolderItem ))
    {
        // Loop through all the properties for our new magic item and copy them over to the placeholder item
        for( var itemProp in rndJewelry )
        {
            if( itemProp != null && itemProp != "serial" && itemProp != "scripttrigger" && itemProp != "scriptTriggers"
                    && itemProp != "sellvalue" && itemProp != "buyvalue" && itemProp != "restock")
            {
                if( typeof( rndJewelry[itemProp] ) != "undefined" && rndJewelry[itemProp] != null )
                {
                    if( itemProp == "race" && rndJewelry.race != null )
                        placeHolderItem.race = rndJewelry.race.id;
                    else
                    {
                        placeHolderItem[itemProp] = rndJewelry[itemProp];
                    }
                }
            }
        }

        // Copy scripttriggers too!
        var scriptTriggerList = rndJewelry.scriptTriggers;
        for( var i = 0; i < scriptTriggerList.length; i++ )
        {
            if( scriptTriggerList[i] != 0 && scriptTriggerList[i] != magicItemScriptID )
                placeHolderItem.AddScriptTrigger( scriptTriggerList[i] );
        }
    }
    return rndJewelry;
}

function calcJewelrySpellBonus( rndJewelry )
{
    // Define some variables
    var spellBonusName = "";
    var spellCircle = 0;
    var spellNumber = 0;
    var spellCharges = 0;

    var rndNum = RandomNumber( 0, 100 );
    if ( rndNum <= 10 ) // Nightsight;  11% chance
    {
        spellCircle = 1;
        spellCharges = 50;
        spellBonusName = "Feline Sight";
        spellNumber = 6;       
    }
    else if ( rndNum <= 20 ) // Heal;  10% chance
    {
        spellCircle = 1;
        spellCharges = 50;
        spellBonusName = "Healing Light Wounds";
        spellNumber = 4;       
    }
    else if ( rndNum <= 30 ) // Cure;  10% chance
    {
        spellCircle = 2;
        spellCharges = 40;
        spellBonusName = "Remove Poisons";
        spellNumber = 11;      
    }
    else if ( rndNum <= 40 ) // Strength;  10% chance
    {
        spellCircle = 2;
        spellCharges = 40;
        spellBonusName = "Might";
        spellNumber = 16;      
    }
    else if ( rndNum <= 50 ) // Agility;  10% chance
    {
        spellCircle = 2;
        spellCharges = 40;
        spellBonusName = "Quickness";
        spellNumber = 9;       
    }
    else if ( rndNum <= 60 ) // Cunning;  5% chance
    {
        spellCircle = 2;
        spellCharges = 40;
        spellBonusName = "Intellect";
        spellNumber = 10;      
    }
    else if ( rndNum <= 65 ) // Arch Cure;  5% chance
    {
        spellCircle = 4;
        spellCharges = 30;
        spellBonusName = "Cleanse Poisons";
        spellNumber = 25;      
    }
    else if ( rndNum <= 70 ) // Greater Heal;  5% chance
    {
        spellCircle = 4;
        spellCharges = 30;
        spellBonusName = "Healing Severe Wounds";
        spellNumber = 10;      
    }
    else if ( rndNum <= 75 ) // Telekinesis;  5% chance
    {
        spellCircle = 3;
        spellCharges = 35;
        spellBonusName = "Invisible Handling";
        spellNumber = 21;      
    }
    else if ( rndNum <= 80 ) // Teleport;  5% chance
    {
        spellCircle = 3;
        spellCharges = 35;
        spellBonusName = "Teleportation";
        spellNumber = 22;      
    }
    else if ( rndNum <= 85 ) // Incognito;  5% chance
    {
        spellCircle = 5;
        spellCharges = 25;
        spellBonusName = "Identity Concealment";
        spellNumber = 35;      
    }
    else if ( rndNum <= 89 ) // Polymorph;  4% chance
    {
        spellCircle = 7;
        spellCharges = 25;
        spellBonusName = "Shape Changing";
        spellNumber = 56;      
    }
    else if ( rndNum <= 91 ) // Summon Creature;  2% chance
    {
        spellCircle = 5;
        spellCharges = 25;
        spellBonusName = "Creature Summoning";
        spellNumber = 10;      
    }
    else if ( rndNum <= 93 ) // Magic Reflection;  2% chance
    {
        spellCircle = 5;
        spellCharges = 25;
        spellBonusName = "Magical Protection";
        spellNumber = 36;      
    }
    else if ( rndNum <= 95 ) // Dispell;  2% chance
    {
        spellCircle = 6;
        spellCharges = 20;
        spellBonusName = "Dispell Magic";
        spellNumber = 41;      
    }
    else if ( rndNum <= 97 ) // Invisibility;  2% chance
    {
        spellCircle = 6;
        spellCharges = 20;
        spellBonusName = "Invisibility";
        spellNumber = 44;      
    }
    else if ( rndNum <= 99 ) // Reveal;  2% chance
    {
        spellCircle = 6;
        spellCharges = 20;
        spellBonusName = "Revealing";
        spellNumber = 48;      
    }
    else  // Summon Elemental, Demon, or Resurrection;  1% chance
    {
        spellCircle = 8;
        spellCharges = 10;
        var rndNum1 = RandomNumber( 1, 5 );
        switch( rndNum1 )
        {
            case 1:  // 33% chance to get resurrection
            case 2:
                spellBonusName = "Raising";
                spellNumber = 59;      
                break;
            default:        //  Nope, so get one of the big summonings
                var rndNum2 = RandomNumber( 1, 5 );
                switch( rndNum2 )
                {
                    case 1:
                        spellBonusName = "Earth Summoning";
                        spellNumber = 62;      
                        break;
                    case 2:
                        spellBonusName = "Air Summoning";
                        spellNumber = 60;      
                        break;
                    case 3:
                        spellBonusName = "Fire Summoning";
                        spellNumber = 63;      
                        break;
                    case 4:
                        spellBonusName = "Water Summoning";
                        spellNumber = 64;      
                        break;
                    default:
                        spellBonusName = "Demon Summoning";
                        spellNumber = 61;  
                }
        }
    }

    //Let's add that bonus-spell
    rndJewelry.type = 15;
    rndJewelry.morex = spellCircle;
    rndJewelry.morey = spellNumber;
    rndJewelry.morez = spellCharges;

    // Let's add the bonus-name
    rndJewelry.name2 += spellBonusName;
}

// ---------------------
// CREATE MAGICAL CLOTHING
// ---------------------

function CreateMagicClothes( tierNum, placeHolderItem )
{
    // Create random item from chosen tier
    var rndClothing;
    var rndClothingNum;
    switch( tierNum )
    {
        case 1:
            rndClothingNum = RandomNumber( 0, tier1clothing.length - 1);
            rndClothing = CreateDFNItem( null, null, tier1clothing[rndClothingNum], 1, "ITEM", false );
            break;
        default:
            rndClothingNum = RandomNumber( 0, tier2clothing.length - 1);
            rndClothing = CreateDFNItem( null, null, tier2clothing[rndClothingNum], 1, "ITEM", false );
            break;
    }

    if( !ValidateObject( rndClothing ))
    {
        Console.Error( "Unable to spawn DFN item from tier-array " + tierNum + " with array-position (rndArmorNum) " + rndArmorNum );
        return null;
    }

    // Handle armor bonuses
    // Should we add a HP bonus, an AR bonus - or both?
    var rndBonus = RandomNumber( 0, 100 );
    var addHpBonus = false;
    var addArmorBonus = false;
    // Sell value based on added bonuses
    var baseClothingValue = placeHolderItem.buyvalue;
    rndClothing.buyvalue = placeHolderItem.buyvalue;
    // Increase rndBonus by 2.5 to 12.5 extra depending on maxTierLevel of NPC, so
    // the higher the maxTierLevel, the less chance of getting rubbish magical items!
    rndBonus = rndBonus + ( Math.round( maxTierLevel * 2.5 ));
    rndBonus = Math.round( rndBonus );
    rndClothing.intadd=5;
   
    if( rndBonus >= 0 && rndBonus < 95 )
    {
        // 1 Magical Effect
        iNum = RandomNumber( 0, 1 );
        if( iNum == 0 )
        {
            //Only HP Bonus
            addHpBonus = true;
        }
        else if( iNum == 1 )
        {
            //Only AR Bonus
            addArmorBonus = true;
        }
    }
    else
    {
        // 2 Magical Effects
        addHpBonus = true;
        addArmorBonus = true;
    }

    // First store the original item-name in a tempVariable
    var tempName = rndClothing.name;
    rndClothing.name2 = "";

    // Are we adding HP bonuses?
    if( addHpBonus )
    {
        calcHpBonus( rndClothing, 1 );
        rndClothing.name2 += " ";
        rndClothing.buyvalue += baseClothingValue;
    }

    // Add item-name after HP bonus, but before a potential AR bonus
    rndClothing.name2 += tempName;

    // Are we adding AR bonuses?
    if( addArmorBonus )
    {
        calcArmorBonus( rndClothing );
        rndClothing.buyvalue += baseClothingValue;
    }

    // Are we adding spell bonuses?
    iNum = RandomNumber( 1, 100 );
    if( iNum <= 5 ) // 5% chance of spell bonus on a given magic armor
    {
        if( addArmorBonus )
        {
            rndClothing.name2 += " and ";
        }
        else
        {
            rndClothing.name2 += " of ";
        }

        calcArmorSpellBonus( rndClothing );
        rndClothing.buyvalue *= 2;
        // Add script that handles equip effects to the magic armor
        rndClothing.AddScriptTrigger( armorSpellsScriptID );
    }

    rndClothing.name = "magic " + tempName;

    // Is final name too long? Not much we can do about it, MAX_NAME in UOX3 code is set to 128... Log it anyway, though.
    if( rndClothing.name2.length >= 128 )
    {
        Console.Log( "Magic armor generated with name consisting of 128 or more letters! Serial: " + rndClothing.serial );
    }

    if( outputMagicItemNamesToFile )
        addToDatabase( 1, rndClothing.name2 );

    if( ValidateObject( rndClothing ) && ValidateObject( placeHolderItem ))
    {
        // Loop through all the properties for our new magic item and copy them over to the placeholder item
        for( var itemProp in rndClothing )
        {
            Console.Log( "Property name: " + itemProp + "  -  Set to: " + rndClothing[itemProp] );
            if( itemProp != null && itemProp != "serial" && itemProp != "scripttrigger" && itemProp != "scriptTriggers"
                    && itemProp != "sellvalue" && itemProp != "restock" )
            {
                if( typeof( rndClothing[itemProp] ) != "undefined" && rndClothing[itemProp] != null )
                {
                    if( itemProp == "race" && rndClothing.race != null )
                        placeHolderItem.race = rndClothing.race.id;
                    else
                    {
                        placeHolderItem[itemProp] = rndClothing[itemProp];
                    }
                }
            }
        }

        // Copy scripttriggers too!
        var scriptTriggerList = rndClothing.scriptTriggers;
        for( var i = 0; i < scriptTriggerList.length; i++ )
        {
            if( scriptTriggerList[i] != 0 && scriptTriggerList[i] != magicItemScriptID )
                placeHolderItem.AddScriptTrigger( scriptTriggerList[i] );
        }
    }
    return rndClothing;
}

// Debug-function to output list of names generated by script
function addToDatabase( itemType, rndItemName )
{
    var j = 0;
    var addName = true;
    var magicName = "";
    var mFileWrite = new UOXCFile();
    if( itemType == 0 ) // weapon
        mFileWrite.Open( "magicweapons_list.txt", "a" );
    else
        mFileWrite.Open( "magicarmors_list.txt", "a" );
    mFileWrite.Write( rndItemName + "\n");
    mFileWrite.Close()
    mFileWrite.Free();
}
Attachments
magic_items.js
(55.86 KiB) Downloaded 117 times
Post Reply