mirror of
https://github.com/UOX3DevTeam/UOX3
synced 2026-08-13 12:27:04 -04:00
1675 lines
42 KiB
JavaScript
1675 lines
42 KiB
JavaScript
/// <reference path="../definitions.d.ts" />
|
|
// @ts-check
|
|
// Magical Items, Pre-AoS style
|
|
// v1.01
|
|
// by Xuri
|
|
// Last updated March 17th, 2023
|
|
|
|
// // 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 .hidamage property only
|
|
// 1 = Split the bonus damage between weapon's .lodamage (~50%) and .hidamage (~50%) properties
|
|
// 2 = Apply the full bonus damage to weapon's .lodamage and .hidamage properties equally (Default)
|
|
const dmgBonusType = GetServerSetting( "WeaponDamageBonusType" );
|
|
|
|
// 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 = 45;
|
|
var tier2DropRate = 37;
|
|
var tier3DropRate = 28;
|
|
var tier4DropRate = 16;
|
|
var tier5DropRate = 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
|
|
const tier1weapons = new Array( "0x13E3", "0x13E4", "0x0E81", "0x0E82", "0x13F4", "0x13F5", "0x0FB4", "0x0FB5", "0x0E85", "0x0E86", "0x0EC4", "0x0EC5", "0x0EC2", "0x0EC3", "0x13F6", "0x13F7" );
|
|
// Tier 2: Hatchets, Hammer Picks, Pitchforks, Clubs, Daggers, Longswords
|
|
const tier2weapons = new Array( "0x0F43", "0x0F44", "0x143C", "0x143D", "0x0E87", "0x0E88", "0x13B3", "0x13B4", "0x0F51", "0x0F52", "0x0F60", "0x0F61", "0x13B7", "0x13B8" );
|
|
// Tier 3: Maces, Heavy Crossbows, Mauls, Crossbows, Cutlasses, Viking Swords, Bows, War Maces
|
|
const tier3weapons = new Array( "0x0F5C", "0x0F5D", "0x13FC", "0x13FD", "0x143A", "0x143B", "0x0F4F", "0x0F50", "0x1440", "0x1441", "0x13B9", "0x13BA", "0x13B1", "0x13B2", "0x1406", "0x1407" );
|
|
// 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" );
|
|
|
|
// Magic Wands and gnarled staffs
|
|
const magicWands = new Array( "0x0df2", "0x0df3", "0x0df4", "0x0df5", "0x13f8", "0x13f9" );
|
|
|
|
// (Potentially) create magic item on corpse upon death
|
|
/** @type { ( pDead: Character, iCorpse: Item ) => boolean } */
|
|
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, 4 );
|
|
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;
|
|
}
|
|
|
|
// 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
|
|
/** @type { ( thingCreated: BaseObject, thingType: 0 | 1 ) => void } */
|
|
function onCreateDFN( objMade, objType )
|
|
{
|
|
if( objType == 0 && ValidateObject( objMade ))
|
|
{
|
|
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( 1, 4 );
|
|
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;
|
|
}
|
|
}
|
|
|
|
// 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 )
|
|
{
|
|
// Let's figure out which tier of magic weapons to potentially spawn from
|
|
var tierNum = RandomNumber( 1, 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 ring
|
|
magicItem = CreateMagicRing( tierNum, placeHolderItem );
|
|
break;
|
|
/*case 4: // magic clothes ??
|
|
break;
|
|
default:
|
|
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 );
|
|
|
|
var addHpBonus = false;
|
|
var addAccBonus = false;
|
|
var addDmgBonus = false;
|
|
var addSilverBonus = false;
|
|
var valueBonus = 0;
|
|
|
|
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;
|
|
}
|
|
valueBonus = 2.0;
|
|
}
|
|
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;
|
|
}
|
|
valueBonus = 3.0;
|
|
}
|
|
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;
|
|
}
|
|
valueBonus = 4.0;
|
|
}
|
|
else if( rndBonus >= 110 )
|
|
{
|
|
// 4 Magical Effects
|
|
addHpBonus = true;
|
|
addAccBonus = true;
|
|
addDmgBonus = true;
|
|
addSilverBonus = true;
|
|
valueBonus = 5.0;
|
|
}
|
|
|
|
// Add value bonus
|
|
rndWeapon.buyvalue *= valueBonus;
|
|
rndWeapon.sellvalue *= valueBonus;
|
|
|
|
// 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 );
|
|
}
|
|
|
|
// Are we adding ACC bonuses?
|
|
if( addAccBonus )
|
|
{
|
|
CalcAccuracyBonus( rndWeapon, addHpBonus );
|
|
}
|
|
else if( addHpBonus )
|
|
{
|
|
rndWeapon.name2 += " ";
|
|
}
|
|
|
|
// Add Silver bonus?
|
|
if( addSilverBonus )
|
|
{
|
|
rndWeapon.name2 += "silver ";
|
|
rndWeapon.race = 11;
|
|
}
|
|
|
|
// 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 );
|
|
}
|
|
|
|
// Are we adding Spell bonuses?
|
|
iNum = RandomNumber( 1, 100 );
|
|
// if( iNum <= 5 ) // 5% chance of spell bonus for a given magical weapon
|
|
if( iNum > 0 ) // 5% chance of spell bonus for a given magical weapon
|
|
{
|
|
if( addDmgBonus )
|
|
{
|
|
rndWeapon.name2 += " and ";
|
|
}
|
|
else
|
|
{
|
|
rndWeapon.name2 += " of ";
|
|
}
|
|
|
|
CalcWeaponSpellBonus( rndWeapon );
|
|
}
|
|
|
|
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 != "att" )
|
|
{
|
|
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 = "substantial";
|
|
break;
|
|
case 3:
|
|
hpBonus = 30;
|
|
hpBonusName = "massive";
|
|
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 )
|
|
{
|
|
// Apply full bonus to .hidamage
|
|
rndWeapon.hidamage += dmgBonus;
|
|
}
|
|
else if( dmgBonusType == 1 )
|
|
{
|
|
// Split bonus equally
|
|
rndWeapon.lodamage += ( dmgBonus / 2 );
|
|
rndWeapon.hidamage += ( dmgBonus / 2 );
|
|
}
|
|
else
|
|
{
|
|
// Apply full bonus to both
|
|
rndWeapon.lodamage += dmgBonus;
|
|
rndWeapon.hidamage += dmgBonus;
|
|
}
|
|
|
|
// 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( 5, 30 );
|
|
}
|
|
else if( iNum == 1 )
|
|
{
|
|
spellBonusName = "Feeblemindedness";
|
|
spellNumber = 3;
|
|
spellCharges = RandomNumber( 5, 30 );
|
|
}
|
|
else
|
|
{
|
|
spellBonusName = "Weakness";
|
|
spellNumber = 8;
|
|
spellCharges = RandomNumber( 5, 30 );
|
|
}
|
|
break;
|
|
case 2:
|
|
var iNum = RandomNumber( 0, 100 );
|
|
if( iNum < 45 ) // 45% chance
|
|
{
|
|
spellBonusName = "Burning"; // Magic Arrow
|
|
spellCircle = 1;
|
|
spellNumber = 5;
|
|
spellCharges = RandomNumber( 5, 25 );
|
|
}
|
|
else if( iNum < 80 ) // 35% chance
|
|
{
|
|
spellBonusName = "Wounding"; // Harm
|
|
spellCircle = 2;
|
|
// spellNumber = 4;
|
|
spellNumber = 12;
|
|
spellCharges = RandomNumber( 5, 25 );
|
|
}
|
|
else // 20% chance
|
|
{
|
|
spellBonusName = "Daemon's Breath"; // Fireball
|
|
spellCircle = 3;
|
|
// spellNumber = 2;
|
|
spellNumber = 18;
|
|
spellCharges = RandomNumber( 5, 25 );
|
|
}
|
|
break;
|
|
case 3:
|
|
spellCircle = 4;
|
|
var iNum = RandomNumber( 0, 1 );
|
|
if( iNum == 0 )
|
|
{
|
|
spellBonusName = "Mages Bane"; // Mana Drain
|
|
// spellNumber = 7;
|
|
spellNumber = 31;
|
|
spellCharges = RandomNumber( 5, 20 );
|
|
}
|
|
else
|
|
{
|
|
spellBonusName = "Evil"; // Curse
|
|
// spellNumber = 3;
|
|
spellNumber = 27;
|
|
spellCharges = RandomNumber( 5, 20 );
|
|
}
|
|
break;
|
|
case 4:
|
|
spellBonusName = "Thunder"; // Lightning
|
|
spellCircle = 4;
|
|
// spellNumber = 6;
|
|
spellNumber = 30;
|
|
spellCharges = RandomNumber( 5, 15 );
|
|
break;
|
|
case 5:
|
|
spellBonusName = "Ghoul's Touch"; // Paralyze
|
|
spellCircle = 5;
|
|
// spellNumber = 6;
|
|
spellNumber = 38;
|
|
spellCharges = RandomNumber( 5, 10 );
|
|
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;
|
|
|
|
// 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 += " ";
|
|
}
|
|
|
|
// Add item-name after HP bonus, but before a potential AR bonus
|
|
rndArmor.name2 += tempName;
|
|
|
|
// Are we adding AR bonuses?
|
|
if( addArmorBonus )
|
|
{
|
|
CalcArmorBonus( rndArmor );
|
|
}
|
|
|
|
// 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 );
|
|
|
|
// 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" )
|
|
{
|
|
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 = "Strength";
|
|
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 = "Night 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 = "Strength";
|
|
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 = "Night 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 = "Curse";
|
|
spellCircle = 4;
|
|
spellNumber = 27;
|
|
spellCharges = RandomNumber( 5, 20 );
|
|
}
|
|
break;
|
|
default:
|
|
// Fallback, just in case...
|
|
spellBonusName = "Night 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 )
|
|
{
|
|
if( itemProp != null && itemProp != "serial" && itemProp != "scripttrigger" && itemProp != "scriptTriggers" )
|
|
{
|
|
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 );
|
|
|
|
switch( bonusTier )
|
|
{
|
|
case 1: // Tier 1 - Item ID, Heal
|
|
spellCircle = 1;
|
|
spellCharges = RandomNumber( 5, 125 );
|
|
var iNum = RandomNumber( 0, 1 );
|
|
if( iNum == 0 ) // 50%, or 13/26
|
|
{
|
|
spellBonusName = "Identification";
|
|
spellNumber = 65;
|
|
}
|
|
else if( iNum == 1 ) // 50%, or 13/26
|
|
{
|
|
spellBonusName = "Heal";
|
|
spellNumber = 4;
|
|
}
|
|
break;
|
|
case 2: // Tier 2 - Clumsy, Feeblemind, Weaken
|
|
spellCircle = 1;
|
|
spellCharges = RandomNumber( 5, 100 );
|
|
var iNum = RandomNumber( 0, 2 );
|
|
if( iNum == 0 ) // 33%, or 11/33
|
|
{
|
|
spellBonusName = "Clumsiness";
|
|
spellNumber = 1;
|
|
}
|
|
else if( iNum == 1 ) // 33%, or 11/33
|
|
{
|
|
spellBonusName = "Feeblemindedness";
|
|
spellNumber = 3;
|
|
}
|
|
else // 33%, or 11/33
|
|
{
|
|
spellBonusName = "Weakness";
|
|
spellNumber = 8;
|
|
}
|
|
break;
|
|
case 3: // Tier 3 - Magic Arrow, Harm, Greater Heal, Fireball
|
|
spellCharges = RandomNumber( 5, 75 );
|
|
var iNum = RandomNumber( 1, 100 );
|
|
if( iNum <= 31 ) // 31% chance, or 10/32
|
|
{
|
|
spellBonusName = "Burning"; // Magic Arrow
|
|
spellCircle = 1;
|
|
spellNumber = 5;
|
|
}
|
|
else if( iNum <= 56 ) // 25% chance, or 8/32
|
|
{
|
|
spellBonusName = "Wounding"; // Harm
|
|
spellCircle = 2;
|
|
spellNumber = 12;
|
|
}
|
|
else if( iNum <= 78 ) // 22% chance, or 7/32
|
|
{
|
|
spellBonusName = "Greater Heal"; // Greater Heal
|
|
spellCircle = 4;
|
|
spellNumber = 29;
|
|
}
|
|
else // 22% chance, or 7/32
|
|
{
|
|
spellBonusName = "Daemon's Breath"; // Fireball
|
|
spellCircle = 3;
|
|
spellNumber = 18;
|
|
}
|
|
break;
|
|
case 4: // Tier 4 - Lightning, Mana Drain
|
|
spellCircle = 4;
|
|
spellCharges = RandomNumber( 5, 50 );
|
|
var iNum = RandomNumber( 1, 100 );
|
|
if( iNum <= 63 ) // 63% chance, or 5/8
|
|
{
|
|
spellBonusName = "Mages Bane"; // Mana Drain
|
|
spellNumber = 31;
|
|
}
|
|
else // 27% chance, or 3/8
|
|
{
|
|
spellBonusName = "Thunder"; // Lightning
|
|
spellNumber = 30;
|
|
}
|
|
break;
|
|
case 5: // Tier 5 - Paralyze
|
|
spellBonusName = "Mage's Bane"; // Paralyze
|
|
spellCircle = 5;
|
|
spellNumber = 38;
|
|
spellCharges = RandomNumber( 5, 25 );
|
|
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 RINGS
|
|
// ---------------------
|
|
|
|
function CreateMagicRing( tierNum, placeHolderItem )
|
|
{
|
|
// Create random magic ring
|
|
var rndRing;
|
|
var rndRingNum;
|
|
|
|
// Create a ring object
|
|
rndRing = CreateDFNItem( null, null, "0x108a", 1, "ITEM", false );
|
|
|
|
if( !ValidateObject( rndRing ))
|
|
{
|
|
Console.Error( "Unable to spawn magic ring 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 = rndRing.name;
|
|
rndRing.name2 = rndRing.name;
|
|
|
|
rndRing.name2 += " of ";
|
|
CalcRingSpellBonus( rndRing );
|
|
|
|
rndRing.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( rndRing.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, rndRing.name2 );
|
|
|
|
if( ValidateObject( rndRing ) && ValidateObject( placeHolderItem ))
|
|
{
|
|
// Loop through all the properties for our new magic item and copy them over to the placeholder item
|
|
for( var itemProp in rndRing )
|
|
{
|
|
if( itemProp != null && itemProp != "serial" && itemProp != "scripttrigger" && itemProp != "scriptTriggers" )
|
|
{
|
|
if( typeof( rndRing[itemProp] ) != "undefined" && rndRing[itemProp] != null )
|
|
{
|
|
if( itemProp == "race" && rndRing.race != null )
|
|
{
|
|
placeHolderItem.race = rndRing.race.id;
|
|
}
|
|
else
|
|
{
|
|
placeHolderItem[itemProp] = rndRing[itemProp];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Copy scripttriggers too!
|
|
var scriptTriggerList = rndRing.scriptTriggers;
|
|
for( var i = 0; i < scriptTriggerList.length; i++ )
|
|
{
|
|
if( scriptTriggerList[i] != 0 && scriptTriggerList[i] != magicItemScriptID )
|
|
{
|
|
placeHolderItem.AddScriptTrigger( scriptTriggerList[i] );
|
|
}
|
|
}
|
|
}
|
|
return rndRing;
|
|
}
|
|
|
|
function CalcRingSpellBonus( rndWand )
|
|
{
|
|
// Define some variables
|
|
var spellBonusName = "";
|
|
var spellCircle = 0;
|
|
var spellNumber = 0;
|
|
var spellCharges = 0;
|
|
|
|
var rndNum = RandomNumber( 0, 1 );
|
|
|
|
switch( rndNum )
|
|
{
|
|
case 0: // Teleport
|
|
spellCircle = 3
|
|
spellCharges = RandomNumber( 5, 25 );
|
|
spellBonusName = "Teleport";
|
|
spellNumber = 22;
|
|
break;
|
|
case 1: // Invisibility
|
|
spellCircle = 6
|
|
spellCharges = RandomNumber( 5, 25 );
|
|
spellBonusName = "Invisibility";
|
|
spellNumber = 44;
|
|
break;
|
|
default:
|
|
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;
|
|
}
|